From 094535c010320967639e8e86f974d878e80baa72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Frings-F=C3=BCrst?= Date: Fri, 1 May 2015 16:13:57 +0200 Subject: Imported Upstream version 1.7.0 --- rspl/scat.c | 1641 +++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 980 insertions(+), 661 deletions(-) (limited to 'rspl/scat.c') diff --git a/rspl/scat.c b/rspl/scat.c index ec7e99c..f1535fa 100644 --- a/rspl/scat.c +++ b/rspl/scat.c @@ -1,4 +1,6 @@ +// current scat.c with V1.6.3 position curve rspl setup code + /* * Argyll Color Correction System * Multi-dimensional regularized splines data fitter @@ -126,12 +128,18 @@ #define DEFAVGDEV 0.5 /* Default average deviation % */ /* algorithm parameters [Release defaults] */ -#undef POINTWEIGHT /* [Undef] Increas smoothness weighting proportional to number of points */ #define INCURVEADJ /* [Defined] Adjust smoothness criteria for input curve grid spacing */ -#define ENABLE_2PASSSMTH /* [Define] Enable 2 pass smooth using Gaussian filter */ -#define ENABLE_EXTRAFIT /* [Undef] Enable the extra fit option. Good to combat high smoothness. */ +#undef SMOOTH2 /* [Undef] INCOMPLETE Use 3nd order smoothness rather than curvature. */ + /* 2nd order is optimal about 2.5 x lower than 3rd order, */ + /* so an even split between 3rd:2nd would be 1.0 0.4, */ + /* a 9:1 split would be 0.9 0.04 */ + /* This also disables the incorrect scaling of smoothness with */ + /* output range */ +#undef AUTOSM /* [Undef] INCOMPLETE Support auto smoothing using LOOCV */ + +# define CW2 0.9 +# define CW ((1.0 - CW2) * 0.4) -#define TWOPASSORDER 2.0 /* Filter order. 2 = Gaussian */ /* Tuning parameters */ #ifdef NEVER @@ -144,13 +152,12 @@ #define TOL_IMP 1.0 /* Minimum error improvement to continue - reduces accuracy (1.0 == off) */ #undef GRADUATED_TOL /* Speedup attemp - use reduced tollerance for prior grids. */ #define GRATIO 1.5 /* Multi-grid resolution ratio */ -#undef OVERRLX /* Use over relaxation factor when progress slows (worse accuracy ?) */ +#undef OVERRLX /* Use over relaxation factor when progress slows (worse accuracy ?) */ #define JITTERS 0 /* Number of 1D conjugate solve itters */ #define CONJ_TOL 1.0 /* Extra tolereance on 1D conjugate solution times TOL. */ #define MAXNI 16 /* Maximum itteration without checking progress */ //#define SMOOTH 0.000100 /* Set nominal smoothing (1.0) */ #define WEAKW 0.1 /* Weak default function nominal effect (1.0) */ -#define ZFCOUNT 1 /* Extra fit repeats */ #else @@ -166,7 +173,6 @@ #define MAXNI 16 /* [16] Maximum itteration without checking progress */ //#define SMOOTH 0.000100 /* Set nominal smoothing (1.0) */ #define WEAKW 0.1 /* [0.1] Weak default function nominal effect (1.0) */ -#define ZFCOUNT 1 /* [1] Extra fit repeats */ #endif @@ -200,6 +206,9 @@ struct _mgtmp { /* Scattered data fit stuff */ struct { double cw[MXDI]; /* Curvature weight factor */ +#ifdef SMOOTH2 + double cw2[MXDI]; /* Smoothness weight factor */ +#endif } sf; /* Grid points data */ @@ -225,7 +234,6 @@ struct _mgtmp { /* Equation Solution related (Grid point solutions) */ struct { - double **ccv; /* [gno][di] Curvature Compensation Values */ double **A; /* A matrix of interpoint weights A[g.no][q.acols] */ int acols; /* A matrix columns needed */ /* Packed indexes run from 0..acols-1 */ @@ -233,16 +241,60 @@ struct _mgtmp { /* and +/-1 offset in all dimensions, but only the +ve offset */ /* half of the sparse matrix is stored, due to equations */ /* being symetrical. */ - int xcol[HACOMPS+8];/* A array column translation from packed to sparse index */ +#define XCOLPMAX (HACOMPS+8) + int xcol[XCOLPMAX]; /* A array column translation from packed to sparse index */ int *ixcol; /* A array column translation from sparse to packed index */ double *b; /* b vector for RHS of simultabeous equation b[g.no] */ double normb; /* normal of b vector */ double *x; /* x solution to A . x = b */ } q; +#ifdef AUTOSM + struct _loocv *as; /* Auto Smooth Setup information */ +#endif + }; typedef struct _mgtmp mgtmp; +/* ================================================= */ + +#ifdef AUTOSM + +/* Structure to hold LOOCV equations for multi-grid calculations */ +/* One is created for each resolution. Only used in this file. */ +struct _loocv { + mgtmp *m; /* Associated mgtmp */ + + int ndcells; /* Number of cells with at least one data point */ + int *dlist; /* Index of base vertex of cell with at least one data point. */ + /* ndcells will be filled */ + + int *vtx_dlist; /* For base vertex index store the index of the first data point */ + /* within that cell. -1 for no data */ + int *dat_dlist; /* Index by data point, store the index of the next data point */ + /* in the list in the cell. -1 for no more data */ + + double *sm; /* smoothness map grid data values in log space, 0.0 for none */ + + double **As; /* A matrix of smoothness vertex weights */ + double *bs; /* b vector for RHS of smoothness equation */ + +#ifdef SMOOTH2 + double **As2; /* A matrix of smoothness 2 vertex weights */ + double *bs2; /* b vector for RHS of smoothness 2 equation */ +#endif + + double **Ad; /* A matrix of data vertex weights */ + double *bd; /* b vector for RHS of data equation */ + + double **AA; /* A matrix of vertex weights */ + double *bb; /* b vector for RHS of equation */ + double *xx; /* x vector for solution of equation for a given smoothness */ + +}; typedef struct _loocv loocv; + +#endif /* AUTOSM */ + /* ================================================= */ /* Temporary arrays used by cj_line(). We try and avoid */ /* allocating and de-allocating these, and merely expand */ @@ -256,15 +308,91 @@ static void init_cj_arrays(cj_arrays *ta); static void free_cj_arrays(cj_arrays *ta); static int add_rspl_imp(rspl *s, int flags, void *d, int dtp, int dno); -static mgtmp *new_mgtmp(rspl *s, int gres[MXDI], int f); +static mgtmp *new_mgtmp(rspl *s, int gres[MXDI], double smooth, double avgdev, int f, int issm); static void free_mgtmp(mgtmp *m); -static void setup_solve(mgtmp *m); +static void setup_solve(mgtmp *m, mgtmp *sm); static void solve_gres(mgtmp *m, cj_arrays *ta, double tol, int final); static void init_soln(mgtmp *m1, mgtmp *m2); -static void comp_ccv(mgtmp *m); -static void filter_ccv(rspl *s, double stdev); -static void init_ccv(mgtmp *m); -static void comp_extrafit_corr(mgtmp *m); +static double mgtmp_interp(mgtmp *m, double p[MXDI]); +#ifdef AUTOSM +static void setup_sutosmsolve(mgtmp *); +static void comp_fit_errors(mgtmp *m); +static void plot_mgtmp1(mgtmp *m); +#endif /* AUTOSM */ + +static void set_it_info( +rspl *s, +int *tres, /* Single dimension grid resolution for each axis */ +it_info *ii /* it_info to set */ +) { + int bres; /* Biggest resolution */ + int sres; /* Starting resolution */ + double res; + double gratio; + int i, e, f; + + bres = 0; + for (e = 0; e < s->di; e++) { + if (tres[e] > bres) + bres = tres[e]; + } + + /* Figure out how many multigrid steps to use */ +#ifdef SMOOTH2 + sres = 5; /* Start at minimum grid res of 5 */ +#else + sres = 4; /* Start at minimum grid res of 4 */ +#endif + + /* Calculate the resolution scaling ratio and number of itters. */ + gratio = GRATIO; + if (((double)bres/(double)sres) <= gratio) { + ii->niters = 2; + gratio = (double)bres/(double)sres; + } else { /* More than one needed */ + ii->niters = (int)((log((double)bres) - log((double)sres))/log(gratio) + 0.5); + gratio = exp((log((double)bres) - log((double)sres))/(double)ii->niters); + ii->niters++; + } + + /* Allocate space for resolutions */ + if ((ii->ires = imatrix(0, ii->niters, 0, s->di)) == NULL) + error("rspl: malloc failed - ires[][]"); + + /* Fill in the resolution values for each itteration */ + for (res = (double)sres, i = 0; i < ii->niters; i++) { + int ires; + + ires = (int)(res + 0.5); + for (e = 0; e < s->di; e++) { + if ((ires + 1) >= tres[e]) /* If close enough biger than target res. */ + ii->ires[i][e] = tres[e]; + else + ii->ires[i][e] = ires; + } + res *= gratio; + } + + /* Assert */ + for (e = 0; e < s->di; e++) { + if (ii->ires[ii->niters-1][e] != tres[e]) + error("rspl: internal error, final res %d != intended res %d\n", + ii->ires[ii->niters-1][e], tres[e]); + } +} + +static void freeit_info( +rspl *s, +it_info *ii +) { + int i, f; + + if (ii->ires != NULL) { + free_imatrix(ii->ires, 0, ii->niters, 0, s->di); + ii->ires = NULL; + } +} + /* Initialise the regular spline from scattered data */ /* Return non-zero if non-monotonic */ @@ -325,12 +453,7 @@ printf("~1 rspl: flags = 0x%x\n",flags); if (flags & RSPL_NOVERBOSE) /* Turn off progress messages to stdout */ s->verbose = 0; -#ifdef ENABLE_2PASSSMTH - s->tpsm = (flags & RSPL_2PASSSMTH) ? 1 : 0; /* Enable 2 pass smoothing */ -#endif -#ifdef ENABLE_EXTRAFIT - s->zf = (flags & RSPL_EXTRAFIT2) ? 2 : 0; /* Enable extra fitting effort */ -#endif + s->ausm = (flags & RSPL_AUTOSMOOTH) ? 1 : 0; /* Enable auto smoothing */ s->symdom = (flags & RSPL_SYMDOMAIN) ? 1 : 0; /* Turn on symetric smoothness with gres */ /* Save smoothing factor and Average Deviation */ @@ -485,66 +608,14 @@ printf("~1 rspl: flags = 0x%x\n",flags); /* Allocate the grid data */ alloc_grid(s); - /* Zero out the re-usable mgtmps */ - for (f = 0; f < s->fdi; f++) { - s->mgtmps[f] = NULL; - } - - { - int sres; /* Starting resolution */ - double res; - double gratio; - - /* Figure out how many multigrid steps to use */ - sres = 4; /* Else start at minimum grid res of 4 */ - - /* Calculate the resolution scaling ratio and number of itters. */ - gratio = GRATIO; - if (((double)s->g.bres/(double)sres) <= gratio) { - s->niters = 2; - gratio = (double)s->g.bres/(double)sres; - } else { /* More than one needed */ - s->niters = (int)((log((double)s->g.bres) - log((double)sres))/log(gratio) + 0.5); - gratio = exp((log((double)s->g.bres) - log((double)sres))/(double)s->niters); - s->niters++; - } - - /* Allocate space for resolutions and mgtmps pointers */ - if ((s->ires = imatrix(0, s->niters, 0, s->di)) == NULL) - error("rspl: malloc failed - ires[][]"); - - for (f = 0; f < s->fdi; f++) { - if ((s->mgtmps[f] = (void *) calloc(s->niters, sizeof(void *))) == NULL) - error("rspl: malloc failed - mgtmps[]"); - } - - /* Fill in the resolution values for each itteration */ - for (res = (double)sres, i = 0; i < s->niters; i++) { - int ires; - - ires = (int)(res + 0.5); - for (e = 0; e < s->di; e++) { - if ((ires + 1) >= s->g.res[e]) /* If close enough biger than target res. */ - s->ires[i][e] = s->g.res[e]; - else - s->ires[i][e] = ires; - } - res *= gratio; - } - - /* Assert */ - for (e = 0; e < s->di; e++) { - if (s->ires[s->niters-1][e] != s->g.res[e]) - error("rspl: internal error, final res %d != intended res %d\n", - s->ires[s->niters-1][e], s->g.res[e]); - } - - } + /* Setup the number of itterations and resolution for each itteration */ + set_it_info(s, s->g.res, &s->ii); /* Do the data point fitting */ return add_rspl_imp(s, 0, d, dtp, dno); } +/* Weighting adjustment values */ double adjw[21] = { 7.0896971822529019e-278, 2.7480236142217909e+233, 1.4857837676559724e+166, 1.3997102851752585e-152, 1.3987140593588909e-076, 2.8215833239257504e+243, @@ -555,6 +626,89 @@ double adjw[21] = { 3.2368131456774088e+262, 6.5639459298208554e+045, 2.0087765219520138e-139 }; +/* Do the fitting for one output plane */ +static mgtmp * +fit_rspl_plane_imp( +rspl *s, /* this */ +int f, /* Output plane */ +it_info *ii, /* resolution info */ +double smooth, /* Smoothing factor */ +double avgdev, /* Average deviation to use to set smoothness */ +//mgtmp *sm, /* Optional smoothness map */ +cj_arrays *ta /* Temporary array */ +) { + int i, nn; /* Multigreid resolution itteration index */ + mgtmp *pm = NULL, *m = NULL; + mgtmp *psm = NULL, *sm = NULL; /* Smoothing map */ + + /* For each resolution (itteration) */ + for (nn = 0; nn < ii->niters; nn++, pm = m) { + + m = new_mgtmp(s, ii->ires[nn], smooth, avgdev, f, 0); + + // ~~~ want setup solve after creating sm, + // but can't setup initial values until after setup_solve + // because m->q.x needs to be allocated + setup_solve(m, sm); + + if (nn == 0) { /* Make sure we have an initial x[] */ +#ifdef AUTOSM + Create sm and set initial values +~~~~ + sm = new_mgtmp(s, ii->ires[nn], smooth, avgdev, f, 1); + for (i = 0; i < sm->g.no; i++) + sm->as.sm[i] = m->sf.cw[e]; /* Value from opt_smooth() */ + /* ?? how to handle cw2[] etc. ? */ + +#endif /* AUTOSM */ + + for (i = 0; i < m->g.no; i++) + m->q.x[i] = s->d.va[f]; /* Start with average data value */ + } else { + init_soln(m, pm); /* Scale from previous resolution */ + free_mgtmp(pm); /* Free previous grid res solution */ + pm = NULL; + +#ifdef AUTOSM + init_soln(sm, psm); /* Scale from previous resolution */ + free_mgtmp(psm); /* Free previous grid res solution */ + psm = NULL; +#endif + } + + solve_gres(m, ta, +#if defined(GRADUATED_TOL) + TOL * s->g.res[s->g.brix]/s->ires[nn][s->g.brix], +#else + TOL, +#endif + ii->ires[nn][s->g.brix] >= s->g.res[s->g.brix]); /* Use itterative */ + +#ifdef DEBUG + { + int k, gno = m->g.no; + double *x = m->q.x; /* x vector for result */ + printf("Plane %d res %d solution values:\n",f,ii->ires[nn][0]); + for (k = 0; k < gno; k++) + printf("x[%d] = %f\n",k,x[k]); + printf("\n"); + } +#endif /* DEBUG */ + +#ifdef AUTOSM + if (nn < (ii->niters-1)) { + + setup_sutosmsolve(sm); + + } +#endif + psm = sm; + } /* Next resolution */ + + /* return the final resolution mgtmp */ + return m; +} + /* Do the work of initialising from initial data points. */ /* Return non-zero if non-monotonic */ static int @@ -578,6 +732,10 @@ add_rspl_imp( return 0; } +#ifdef DEBUG + printf("add_rspl_imp: flags 0x%x, dno %d, dtp %d\n",flags,dno,dtp); +#endif + /* Allocate space for points */ /* Allocate the scattered data space */ if ((s->d.a = (rpnts *) malloc(sizeof(rpnts) * dno)) == NULL) @@ -592,9 +750,9 @@ add_rspl_imp( for (e = 0; e < s->di; e++) s->d.a[n].p[e] = dp[i].p[e]; for (f = 0; f < s->fdi; f++) { - s->d.a[n].cv[f] = s->d.a[n].v[f] = dp[i].v[f]; s->d.a[n].k[f] = 1.0; /* Assume all data points have same weight */ +// s->d.a[n].fe = 0.0; } } } else if (dtp == 1) { /* Per data point weight */ @@ -605,9 +763,9 @@ add_rspl_imp( for (e = 0; e < s->di; e++) s->d.a[n].p[e] = dp[i].p[e]; for (f = 0; f < s->fdi; f++) { - s->d.a[n].cv[f] = s->d.a[n].v[f] = dp[i].v[f]; s->d.a[n].k[f] = dp[n].w; /* Weight specified */ +// s->d.a[n].fe = 0.0; } } } else { /* Per data point output weight */ @@ -618,9 +776,9 @@ add_rspl_imp( for (e = 0; e < s->di; e++) s->d.a[n].p[e] = dp[i].p[e]; for (f = 0; f < s->fdi; f++) { - s->d.a[n].cv[f] = s->d.a[n].v[f] = dp[i].v[f]; s->d.a[n].k[f] = dp[n].w[f]; /* Weight specified */ +// s->d.a[n].fe = 0.0; } } } @@ -628,89 +786,79 @@ add_rspl_imp( init_cj_arrays(&ta); /* Zero temporary arrays */ - if (s->verbose && s->zf) - printf("Doing extra fitting\n"); + if (s->verbose && s->ausm) { +#ifdef AUTOSM + printf("Doing automatic local smoothing optimization\n"); +#else + printf("Automatic local smoothing flag ignored !!!\n"); +#endif + } /* Do fit of grid to data for each output dimension */ for (f = 0; f < fdi; f++) { - int nn = 0; /* Multigreid resolution itteration index */ - int zfcount = ZFCOUNT; /* Number of extra fit adjustments to do */ - int donezf = 0; /* Count - number of extra fit adjustments done */ float *gp; mgtmp *m = NULL; - for (donezf = 0; donezf <= s->zf; donezf++) { /* For each extra fit pass */ +#ifdef NEVER // ~~99 remove this + mgtmp *sm = NULL; /* Auto smoothness map */ - for (s->tpsm2 = 0; s->tpsm2 <= s->tpsm; s->tpsm2++) { /* For passes of 2 pass smoothing */ + /* If auto smoothness, create smoothing map */ + if (s->ausm) { + int res[MXDI]; + int mxres[5] = { 0, 101, 51, 17, 11 }; + int smres[5] = { 0, 12, 8, 6, 6 }; - /* For each resolution (itteration) */ - for (nn = 0; nn < s->niters; nn++) { + /* Set target resolution for initial fit */ + for (e = 0; e < s->di; e++) { + res[e] = s->g.res[e]; - m = new_mgtmp(s, s->ires[nn], f); - s->mgtmps[f][nn] = (void *)m; + if (res[e] > mxres[s->di]) + res[e] = mxres[s->di]; + } - if (s->tpsm && s->tpsm2 != 0) { /* 2nd pass of 2 pass smoothing */ - init_ccv(m); /* Downsample m->ccv from s->g.ccv */ - } - setup_solve(m); + /* Setup the number of itterations and resolution for each itteration */ + set_it_info(s, res, &s->as_ii); - if (nn == 0) { /* Make sure we have an initial x[] */ - for (i = 0; i < m->g.no; i++) - m->q.x[i] = s->d.va[f]; /* Start with average data value */ - } else { - init_soln(m, s->mgtmps[f][nn-1]); /* Scale from previous resolution */ +printf("~1 s->smooth = %f, avgdev[f] = %f\n",s->smooth, s->avgdev[f]); - free_mgtmp(s->mgtmps[f][nn-1]); /* Free previous grid res solution */ - s->mgtmps[f][nn-1] = NULL; - } + /* First pass fit with heavy smoothing */ + m = fit_rspl_plane_imp(s, f, &s->as_ii, 1.0, 0.1, NULL, &ta); - solve_gres(m, &ta, -#if defined(GRADUATED_TOL) - TOL * s->g.res[s->g.brix]/s->ires[nn][s->g.brix], -#else - TOL, -#endif - s->ires[nn][s->g.brix] >= s->g.res[s->g.brix]); /* Use itterative */ +printf("Initial high smoothing fit of output %d:\n",f); +plot_mgtmp1(m); - } /* Next resolution */ + /* Compute the fit error values from first pass */ + comp_fit_errors(m); /* Compute correction to data target values */ - if (s->tpsm && s->tpsm2 == 0) { - double fstdev; /* Filter standard deviation */ -//printf("~1 setting up second pass smoothing !!!\n"); + free_mgtmp(m); - /* Compute the curvature compensation values from */ - /* first pass final resolution */ - comp_ccv(m); + /* Set target resolution for smoothness map */ + for (e = 0; e < s->di; e++) + res[e] = smres[s->di]; - if (s->smooth >= 0.0) { - /* Compute from: no dim, no data points, avgdev & extrafit */ - fstdev = 0.05 * s->smooth; -fprintf(stderr,"~1 !!! Gaussian smoothing not being computed Using default %f !!!\n",fstdev); - } else { /* Special used to calibrate table */ - fstdev = -s->smooth; - } -//fprintf(stderr,"~1 Gaussian smoothing with fstdev %f !!!\n",fstdev); - /* Smooth the ccv's */ - filter_ccv(s, fstdev); - } - } /* Next two pass smoothing pass */ - if (s->zf) - comp_extrafit_corr(m); /* Compute correction to data target values */ - } /* Next extra fit pass */ - - /* Clean up after 2 pass smoothing */ - s->tpsm2 = 0; - if (s->g.ccv != NULL) { - free_dmatrix(s->g.ccv, 0, s->g.no-1, 0, s->di-1); - s->g.ccv = NULL; + set_it_info(s, res, &s->asm_ii); + + /* Create smoothness map from fit errors */ + sm = fit_rspl_plane_imp(s, -1, &s->asm_ii, -50000, 0.0, NULL, &ta); +// sm = fit_rspl_plane_imp(s, -1, &s->asm_ii, 1000.0, 0.1, NULL, &ta); +printf("Smoothness map for output %d:\n",f); +plot_mgtmp1(sm); } +#endif /* NEVER */ + + /* Fit data for this plane */ + m = fit_rspl_plane_imp(s, f, &s->ii, s->smooth, s->avgdev[f], /* sm, */ &ta); +//printf("Final fit for output %d:\n",f); +//plot_mgtmp1(m); /* Transfer result in x[] to appropriate grid point value */ for (gp = s->g.a, i = 0; i < s->g.no; gp += s->g.pss, i++) gp[f] = (float)m->q.x[i]; - free_mgtmp(s->mgtmps[f][nn-1]); /* Free final resolution entry */ - s->mgtmps[f][nn-1] = NULL; + free_mgtmp(m); /* Free final resolution entry */ + +// if (sm != NULL) /* Free smoothing map */ +// free_mgtmp(sm); } /* Next output channel */ @@ -862,25 +1010,8 @@ init_data(rspl *s) { /* Free the scattered data allocation */ void free_data(rspl *s) { - int i, f; - if (s->ires != NULL) { - free_imatrix(s->ires, 0, s->niters, 0, s->di); - s->ires = NULL; - } - - /* Free up mgtmps */ - for (f = 0; f < s->fdi; f++) { - if (s->mgtmps[f] != NULL) { - for (i = 0; i < s->niters; i++) { - if (s->mgtmps[f][i] != NULL) { - free_mgtmp(s->mgtmps[f][i]); - } - } - free(s->mgtmps[f]); - s->mgtmps[f] = NULL; - } - } + freeit_info(s, &s->ii); if (s->d.a != NULL) { /* Free up the data point data */ free((void *)s->d.a); @@ -929,13 +1060,28 @@ free_data(rspl *s) { /* !!! Possible answer - should be using third order differences */ /* for controlling smoothness, not second order (curvature) ?? */ +/* Should adapt smoothing to noise level in different parts of gamut. */ +/* Fix scaling smoothing to data range bug! */ + +/* Smoothness tweak */ +static double tweak[21] = { + 8.0891733310676571e-263, 1.1269230397087924e+243, 5.5667427967136639e+170, + 4.6422059659371074e-072, 4.7573037006103243e-038, 2.2050803446598081e-152, + 1.9082109674254010e-094, 1.2362202651281476e+262, 1.8334727652805863e+044, + 1.7193993129127580e-139, 8.4028172720870109e-316, 7.7791723264393403e-260, + 4.5505694361996285e+198, 1.4450789782663302e+214, 4.8548304485951407e-033, + 6.0848773033767158e-153, 2.2014810203887549e+049, 6.0451581453053059e-153, + 4.5657997262605343e+233, 1.1415770815909824e+243, 2.0087364177250134e-139 +}; + +#ifndef SMOOTH2 -// ~~99 static double opt_smooth( rspl *s, int di, /* Dimensions */ int ndp, /* Number of data points */ - double ad /* Average sample deviation (proportion of input range) */ + double ad, /* Average sample deviation (proportion of input range) */ + int f /* Output chanel */ ) { int i; double nc; /* Normalised sample count */ @@ -1027,22 +1173,13 @@ static double opt_smooth( } }; - /* Smoothness tweak */ - static double tweak[21] = { - 8.0891733310676571e-263, 1.1269230397087924e+243, 5.5667427967136639e+170, - 4.6422059659371074e-072, 4.7573037006103243e-038, 2.2050803446598081e-152, - 1.9082109674254010e-094, 1.2362202651281476e+262, 1.8334727652805863e+044, - 1.7193993129127580e-139, 8.4028172720870109e-316, 7.7791723264393403e-260, - 4.5505694361996285e+198, 1.4450789782663302e+214, 4.8548304485951407e-033, - 6.0848773033767158e-153, 2.2014810203887549e+049, 6.0451581453053059e-153, - 4.5657997262605343e+233, 1.1415770815909824e+243, 2.0087364177250134e-139 - }; - /* Real world correction factors go here - */ /* None needed at the moment ? */ double rwf[4] = { 1.0, 1.0, 1.0, 1.0 }; /* Factor for each dimension */ -//printf("~1 opt_smooth called with di = %d, ndp = %d, ad = %f\n",di,ndp,ad); +#ifdef DEBUG + printf("opt_smooth called with di = %d, ndp = %d, ad = %e, f = %d\n",di,ndp,ad,f); +#endif if (di < 1) di = 1; nc = pow((double)ndp, 1.0/(double)di); /* Normalised sample count */ @@ -1088,13 +1225,17 @@ static double opt_smooth( } /* Lookup & interpolate the log smoothness factor */ -//printf("~1 di = %d, ncix = %d, adix = %d\n",di,ncix,adix); +#ifdef DEBUG + printf("di = %d, ncix = %d, adix = %d\n",di,ncix,adix); +#endif lsm = smf[di][ncix][adix] * ncw * adw; lsm += smf[di][ncix][adix+1] * ncw * (1.0 - adw); lsm += smf[di][ncix+1][adix] * (1.0 - ncw) * adw; lsm += smf[di][ncix+1][adix+1] * (1.0 - ncw) * (1.0 - adw); -//printf("~1 lsm = %f\n",lsm); +#ifdef DEBUG + printf("lsm = %f\n",lsm); +#endif for (tweakf = 0.0, i = 1; i < 21; i++) tweakf += tweak[i]; @@ -1105,10 +1246,105 @@ static double opt_smooth( /* and correct for the real world with a final tweak table */ sm *= rwf[di]; -//printf("Got log smth %f, returning %1.9f from ncix %d, ncw %f, adix %d, adw %f\n", lsm, sm, ncix, ncw, adix, adw); +#ifdef DEBUG + printf("opt_smooth got sm %e before output range adjustment\n",sm); +#endif +#ifndef SMOOTH2 + /* This is incorrect, but is built into the tables of releases. */ + /* It is one of the things stuffing up XYZ profiles. */ + /* Remove it after re-tuning with SMOOTH2 */ + sm *= s->d.vw[f]; /* Scale curvature weight for data range */ +#endif +#ifdef DEBUG + printf("opt_smooth returning sm %e after output range adjustment\n",sm); +#endif + +#ifdef DEBUG + printf("Got log smth %f, returning %1.9f from ncix %d, ncw %f, adix %d, adw %f\n", lsm, sm, ncix, ncw, adix, adw); +#endif + return sm; +} + +#else /* Smooth 2 */ + +/* - - - - - - - - - - - - - - - - - - - - - - - -*/ +/* Smooth2 optimal smoothness calculation. */ +/* + + This is for 3rd order smoothness, and uses a set of fitted + equations rather than a table. + +*/ + +static double opt_smooth( + rspl *s, + int di, /* Dimensions */ + int ndp, /* Number of data points */ + double ad, /* Average sample deviation (proportion of input range) */ + int f /* Output chanel */ +) { + int i; + double tweakf; + struct { + double nscale, noffset; /* Number data point scale & offset */ + double nmax, nmin; /* Number data point max and min values */ + double dscale, doffset; /* Deviation scale & offset */ + int l_nid; + } params[4] = { + { -6.80, 3.50, -2.00, -8.00, 1.50, -0.7 }, /* 1d */ + { -6.00, -7.50, -1.85, -6.40, 1.60, 0.6 }, /* 2d */ + { -0.84, -0.36, -1.68, -3.70, 1.75, 1.85 }, /* 3d */ + { -4.00, 11.20, -0.75, -2.30, 1.55, 2.35 } /* 4d */ + }; + + /* Real world correction factors go here - */ + /* None needed at the moment ? */ + double rwf[4] = { 0.0, 0.0, 0.0, 0.0 }; /* Log10 factor to add for each dimension */ + + double lndp; /* log10 of ndp */ + double lad; /* log10 of ad */ + double lmin; /* log10 of minimum level */ + double sm, lsm; /* log10 of smoothness needed */ + + if (di < 1) + di = 1; + if (di > 4) + di = 4; + di--; /* Make di 0..3 */ + if (ad <= 1e-9) + ad = 1e-9; + +//printf("~1 opt_smooth2 called with di = %d, nodp = %d, avgdev = %f\n",di,ndp,ad); + + lndp = log10(ndp); + + lmin = lndp * params[di].nscale + params[di].noffset; + if (lmin > params[di].nmax) + lmin = params[di].nmax; + if (lmin < params[di].nmin) + lmin = params[di].nmin; +//printf("lmin = %f from lndp\n",lmin,lndp); + + lad = log10(ad); + lsm = log10(pow(10.0, lmin) + pow(10.0, lad * params[di].dscale + params[di].doffset)); +//printf("lsm = %f from lmin %f lad %f dscale %f doff %f\n",lmin,lmin,lad,params[di].dscale,params[di].doffset); + + /* and correct for the real world with a final tweak table */ + lsm += rwf[di]; + + for (tweakf = 0.0, i = 1; i < 21; i++) + tweakf += tweak[i]; + tweakf *= tweak[0]; + + sm = pow(10.0, lsm * tweakf); + +//printf("Got log smth %f, returning sm %1.9f from di %d, nodp %d, avgdev %f\n", lsm, sm,di+1,ndp,ad); + return sm; } +#endif /* SMOOTH2 */ + /* - - - - - - - - - - - - - - - - - - - - - - - -*/ /* Multi-grid temp structure (mgtmp) routines */ @@ -1117,7 +1353,10 @@ static double opt_smooth( static mgtmp *new_mgtmp( rspl *s, /* associated rspl */ int gres[MXDI], /* resolution to create */ - int f /* output dimension */ + double smooth, /* Smoothing factor */ + double avgdev, /* Average deviation to use to set smoothness */ + int f, /* output dimension */ + int issm /* We are creating a smoothness map */ ) { mgtmp *m; int di = s->di; @@ -1125,6 +1364,9 @@ static mgtmp *new_mgtmp( int gno, nigc; int gres_1[MXDI]; int e, g, n, i; +#ifdef AUTOSM + loocv *as = NULL; +#endif /* Allocate a structure */ if ((m = (mgtmp *) calloc(1, sizeof(mgtmp))) == NULL) @@ -1203,13 +1445,13 @@ static mgtmp *new_mgtmp( } /* Compute curvature weighting for matching intermediate resolutions for */ - /* the number of grid points curvature that is accuumulated, as well as the */ + /* the number of grid points curvature that is accumulated, as well as the */ /* geometric effects of a finer fit to the target surface. */ /* This is all to keep the ratio of sum of smoothness error squared */ /* constant in relationship to the sum of data point error squared. */ for (e = 0; e < di; e++) { double rsm; /* Resolution smoothness factor */ - double smooth; + double smval; if (s->symdom) rsm = m->g.res[e]; /* Relative final grid size */ @@ -1221,25 +1463,32 @@ static mgtmp *new_mgtmp( /* (is ^2 for res. * ^2 with error squared) */ rsm /= nigc; /* Average squared non-smoothness */ - /* 2 pass smoothing */ - if (s->tpsm) { - double lsm; + /* Normal */ + if (smooth >= 0.0) { - lsm = -6.0; - if (s->tpsm2 != 0) /* Two pass smoothing second pass */ - lsm += 2.0; /* Use 100 times the smoothness */ - m->sf.cw[e] = pow(10.0, lsm) * rsm; + /* Use auto smoothing map in setup */ +// if (sm != NULL) { +// smval = 1.0; +// } else { - /* Normal */ + /* Table lookup for optimum smoothing factor */ + smval = opt_smooth(s, di, s->d.no, avgdev, f); +//printf("~1 opt_smooth returned %e\n",smval); +#ifdef SMOOTH2 + m->sf.cw[e] = CW * smooth * smval * rsm; + m->sf.cw2[e] = CW2 * smooth * smval * rsm; +#else + m->sf.cw[e] = smooth * smval * rsm; +//printf("~1 cw[%d] %f = smooth %f * smval %e * rsm %f\n",e,m->sf.cw[e],smooth,smval,rsm); +#endif + /* Special used to calibrate table */ } else { - - if (s->smooth >= 0.0) { - /* Table lookup for optimum smoothing factor */ - smooth = opt_smooth(s, di, s->d.no, s->avgdev[f]); - m->sf.cw[e] = s->smooth * smooth * rsm; - } else { /* Special used to calibrate table */ - m->sf.cw[e] = -s->smooth * rsm; - } +#ifdef SMOOTH2 + m->sf.cw[e] = CW * -smooth * rsm; + m->sf.cw2[e] = CW2 * -smooth * rsm; +#else + m->sf.cw[e] = -smooth * rsm; +#endif } } @@ -1248,6 +1497,33 @@ static mgtmp *new_mgtmp( /* changes in grid resolution and dimensionality. */ m->wdfw = s->weak * WEAKW/(m->g.no * (double)di); +#ifdef AUTOSM + if (s->ausm) { + if ((m->as = (loocv *) calloc(1, sizeof(loocv))) == NULL) + error("rspl: malloc failed - loocv"); + + as = m->as; + as->m = m; + + /* Allocate space for arrays keeping track of */ + /* cells with data points in them. */ + if ((as->dlist = ivector(0, dno-1)) == NULL) + error("rspl: malloc of vector dlist failed"); + + if ((as->vtx_dlist = ivector(0,m->g.no-1)) == NULL) + error("rspl: malloc of vector vtx_dlist failed"); + + for (i = 0; i < m->g.no; i++) + as->vtx_dlist[i] = -1; + + if ((as->dat_dlist = ivector(0, dno-1)) == NULL) + error("rspl: malloc of vector dat_dlist failed"); + + for (i = 0; i < dno; i++) + as->dat_dlist[i] = -1; + } +#endif + /* Allocate space for auiliary data point related info */ if ((m->d = (struct mgdat *) calloc(dno, sizeof(struct mgdat))) == NULL) error("rspl: malloc failed - mgtmp"); @@ -1293,10 +1569,19 @@ static mgtmp *new_mgtmp( printf("%d: %f\n",e,m->d[n].w[e]); } #endif /* DEBUG */ + +#ifdef AUTOSM + if (s->ausm && m->as != NULL) { + /* Add data point to per cell list */ + if (as->vtx_dlist[ix] == -1) + as->dlist[as->ndcells++] = ix; + as->dat_dlist[n] = as->vtx_dlist[ix]; + as->vtx_dlist[i] = n; + } +#endif /* AUTOSM */ } /* Set the solution matricies to unalocated */ - m->q.ccv = NULL; m->q.A = NULL; m->q.ixcol = NULL; m->q.b = NULL; @@ -1305,6 +1590,21 @@ static mgtmp *new_mgtmp( return m; } +#ifdef AUTOSM +/* Completely free an loocv */ +static void free_loocv(loocv *as) { + mgtmp *m = as->m; + rspl *s = m->s; + + free_ivector(as->dlist, 0, s->d.no-1); + free_ivector(as->vtx_dlist, 0, m->g.no-1); + free_ivector(as->dat_dlist, 0, s->d.no-1); + + free(as); +} + +#endif + /* Completely free an mgtmp */ static void free_mgtmp(mgtmp *m) { int e, di = m->s->di, gno = m->g.no; @@ -1313,49 +1613,125 @@ static void free_mgtmp(mgtmp *m) { if (m->g.ipos[e] != NULL) free(m->g.ipos[e]); } - if (m->q.ccv != NULL) - free_dmatrix(m->q.ccv,0,gno-1,0,di-1); free_dvector(m->q.x,0,gno-1); free_dvector(m->q.b,0,gno-1); free((void *)m->q.ixcol); free_dmatrix(m->q.A,0,gno-1,0,m->q.acols-1); free((void *)m->d); + +#ifdef AUTOSM + if (m->as != NULL) + free_loocv(m->as); +#endif free((void *)m); } -/* Initialise the A[][] and b[] matricies ready to solve, given f */ -/* (Can be used to re-initialize an mgtmp for changing curve/extra fit factors) */ -/* We are setting up the matrix equation Ax = b to solve, where the aim is */ -/* to solve the energy minimization problem by setting up a series of interconnected */ -/* equations for each grid node value (x) in which the partial derivative */ -/* of the equation to be minimized is zero. The A matrix holds the dependence on */ -/* the grid points with regard to smoothness and interpolation */ -/* fit to the scattered data points, while b holds constant values (e.g. the data */ -/* point determined boundary conditions). A[][] stores the packed sparse triangular matrix. */ +#ifdef NEVER -/* +/* Return the curreb A[][] * x[] value. */ +/* (We use this to determine smoothness factor sensitivity for each */ +/* point with just smoothness weighting factors present) */ +static double smth_err +( + double **A, /* Sparse A[][] matrix */ + double *x, /* x[] matrix */ + int gno, /* Total number of unknowns */ + int acols, /* Use colums in A[][] */ + int *xcol /* sparse expansion lookup array */ +) { + int i, k; + double rv; - The overall equation to be minimized is: + /* Compute norm of b - A * x */ + rv = 0.0; + for (i = 0; i < gno; i++) { + int k0,k1,k2,k3; + double sm = 0.0; - sum(curvature errors at each grid point) ^ 2 - + sum(data interpolation errors) ^ 2 + /* Diagonal and to right in 4's */ + for (k = 0, k3 = i + xcol[k]; k < acols && k3 < gno; k++, k3 = i + xcol[k]) { + sm += A[i][k] * x[k3]; +//printf("i %d: A[%d][%d] %f * x[%d] %f = %f\n", i, i, k, A[i][k], k3, x[k3], A[i][k] * x[k3]); + } - The way this is solved is to take the partial derivative of - the above with respect to each grid point value, and simultaineously - solve all the partial derivative equations for zero. + /* Left of diagonal in 4's */ + /* (We take advantage of the symetry: what would be in the row */ + /* to the left is repeated in the column above.) */ + for (k = 1, k3 = i-xcol[k]; k < acols && k3 >= 0; k++, k3 = i-xcol[k]) { + sm += A[k3][k] * x[k3]; +//printf("i %d: A[%d][%d] %f * x[%d] %f = %f\n", i, k3, k, A[k3][k], k3, x[k3], A[k3][k] * x[k3]); + } - Each row of A[][] and b[] represents the cooeficients of one of - the partial derivative equations (it does NOT correspond to one - grid points curvature etc.). Because the partial derivative - of any sum term that does not have the grid point in question in it - will have a partial derivative of zero, each row equation consists - of just those terms that have that grid points value in it, + rv += sm * sm; + } + + return rv; +} + + +/* Print out the smoothness error sensitivity for each data location */ +static void +print_smsens(mgtmp *m) { + + rspl *s = m->s; + int di = s->di; + int gno = m->g.no, *gres = m->g.res, *gci = m->g.ci; + int i; + double **A = m->q.A; /* A matrix of interpoint weights */ + int acols = m->q.acols; /* A matrix columns needed */ + int *xcol = m->q.xcol; /* A array column translation from packed to sparse index */ + double *x = m->q.x; /* x vector for result */ + + for (i = 0; i < gno; i++) + x[i] = 0.0; + + for (i = 0; i < gno; i++) { + double ss; + + x[i] = 1.0; + ss = smth_err(A, x, gno, acols, xcol); + x[i] = 0.0; + + printf("Smoothness sens %d = %e\n",i,ss); + } +} + +#endif /* NEVER */ + +/* Initialise the A[][] and b[] matricies ready to solve, given f */ +/* (Can be used to re-initialize an mgtmp for changing curve/extra fit factors) */ +/* We are setting up the matrix equation Ax = b to solve, where the aim is */ +/* to solve the energy minimization problem by setting up a series of interconnected */ +/* equations for each grid node value (x) in which the partial derivative */ +/* of the equation to be minimized is zero. The A matrix holds the dependence on */ +/* the grid points with regard to smoothness and interpolation */ +/* fit to the scattered data points, while b holds constant values (e.g. the data */ +/* point determined boundary conditions). A[][] stores the packed sparse triangular matrix. */ + +/* + + The overall equation to be minimized is: + + sum(curvature errors at each grid point) ^ 2 + + sum(data interpolation errors) ^ 2 + + The way this is solved is to take the partial derivative of + the above with respect to each grid point value, and simultaineously + solve all the partial derivative equations for zero. + + Each row of A[][] and b[] represents the cooeficients of one of + the partial derivative equations (it does NOT correspond to one + grid points curvature etc.). Because the partial derivative + of any sum term that does not have the grid point in question in it + will have a partial derivative of zero, each row equation consists + of just those terms that have that grid points value in it, with the vast majoroty of the sum terms omitted. */ static void setup_solve( - mgtmp *m /* initialized grid temp structure */ +mgtmp *m, /* initialized grid temp structure */ +mgtmp *sm /* Optional smoothing map for ausm mode */ ) { rspl *s = m->s; int di = s->di; @@ -1363,10 +1739,9 @@ static void setup_solve( int *gres = m->g.res, *gci = m->g.ci; int f = m->f; /* Output dimensions being worked on */ - double **ccv = m->q.ccv; /* ccv vector for adjusting simultabeous equation */ double **A = m->q.A; /* A matrix of interpoint weights */ int acols = m->q.acols; /* A matrix packed columns needed */ - int *xcol = m->q.xcol; /* A array column translation from packed to sparse index */ + int *xcol = m->q.xcol; /* A array column translation from packed to sparse index */ int *ixcol = m->q.ixcol; /* A array column translation from sparse to packed index */ double *b = m->q.b; /* b vector for RHS of simultabeous equation */ double *x = m->q.x; /* x vector for LHS of simultabeous equation */ @@ -1374,15 +1749,21 @@ static void setup_solve( double oawt; /* Overall adjustment weight */ double nbsum; /* normb sum */ -//printf("~1 setup_solve got ccv = 0x%x\n",ccv); +#ifdef DEBUG + printf("setup_solve got sm = %p\n",sm); +#endif /* Allocate and init the A array column sparse packing lookup and inverse. */ - /* Note that this only works for a minumum grid resolution of 4. */ + /* Note that this only works for a minumum grid resolution of 4/5. */ /* The sparse di dimension region allowed for is a +/-1 cube around the point */ /* question, plus +/-2 offsets in axis direction only, */ - /* plus +/-3 offset in axis directions if 2nd order smoothing is defined. */ + /* plus +/-3 offset in axis directions if SMOOTH2 is defined. */ if (A == NULL) { /* Not been allocated previously */ +#ifdef SMOOTH2 DCOUNT(gc, MXDIDO, di, -3, -3, 4); /* Step through +/- 3 cube offset */ +#else + DCOUNT(gc, MXDIDO, di, -2, -2, 3); /* Step through +/- 2 cube offset */ +#endif int ix; /* Grid point offset in grid points */ acols = 0; @@ -1405,13 +1786,13 @@ static void setup_solve( /* or if it has exactly one +/-2 and otherwise 0 */ if ((n3 == 0 && n2 == 0) || (n2 == 1 && nz == (di-1)) -#ifdef SMOOTH2 || (n3 == 1 && nz == (di-1)) -#endif /* SMOOTH2*/ ) { for (ix = 0, k = 0; k < di; k++) ix += gc[k] * gci[k]; /* Multi-dimension grid offset */ if (ix >= 0) { + if (acols >= XCOLPMAX) + error("rspl internal: exceeded xcol bounds"); xcol[acols++] = ix; /* We only store half, due to symetry */ } } @@ -1459,7 +1840,6 @@ static void setup_solve( } /* Stash in the mgtmp */ - m->q.ccv = ccv; m->q.A = A; m->q.b = b; m->q.x = x; @@ -1475,6 +1855,13 @@ static void setup_solve( b[i] = 0.0; } + /* Compute adjustment cooeficient */ + { + for (oawt = 0.0, i = 1; i < 21; i++) + oawt += wvals[i]; + oawt *= wvals[0]; + } + /* Production version, without extra edge weight */ /* Accumulate curvature dependent factors to the triangular A matrix. */ @@ -1490,9 +1877,9 @@ static void setup_solve( The old curvature fixed grid spacing equation was: ki * (u[i-1] - 2 * u[i] + u[i+1])^2 with derivatives wrt each node: - ki-1 * 1 * 2 * u[i-1] - ki * -2 * 2 * u[i] - ki+1 * 1 * 2 * u[i+1] + ki-1 * 1 * 2 * eqn(i-1) + ki * -2 * 2 * eqn(i) + ki+1 * 1 * 2 * eqn(i+1) Allowing for scaling of each grid difference by w[i-1] and w[i], where w[i-1] corresponds to the width of cell i-1 to i, @@ -1503,26 +1890,14 @@ static void setup_solve( ki-1 * w[i-1] * w[i-1] * u[i-1] ki * -(w[i-1] + w[i]) * -(w[i-1] + w[i]) * u[i]) ki+1 * w[i] * w[i] * u[i+1] - - The weighting is adjusted to compensate for increased - grid density by the dw weight, and for the different - scaling either side of a grid point with the w0 and w1 scale. - Both are normalised so that the overall smoothness scaling - factor applies. */ +#define V17 /* Enable V1.7 code */ { /* Setting this up from scratch */ - double dwtw[MXDIDO]; /* Density weight normalizer */ - int wtwc[MXDIDO]; +// double dwtw[MXDIDO]; /* Density weight normalizer = average grid widths */ ECOUNT(gc, MXDIDO, di, 0, gres, 0); - for (oawt = 0.0, i = 1; i < 21; i++) - oawt += wvals[i]; - oawt *= wvals[0]; - -#define EN_DW /* Enable grid density weighting */ -#define EN_CW /* Enable grid scale weighting */ - +#ifdef NEVER /* We're not using density adjustment */ /* Compute the ipos[] weight normalisation factors */ for (e = 0; e < di; e++) { if (m->g.ipos[e] == NULL) @@ -1532,108 +1907,305 @@ static void setup_solve( double w; w = fabs(m->g.ipos[e][i] - m->g.ipos[e][i-1]); //printf("[%d][%d] w = %f\n",e,i,w); - dwtw[e] += w; +// dwtw[e] += w; + dwtw[e] += 1.0/w; } dwtw[e] /= (gres[e] - 1.0); /* Average weights */ + dwtw[e] = 1.0/dwtw[e]; //printf("dwtw[%d] = %f\n",e,dwtw[e]); } +#endif EC_INIT(gc); for (i = 0; i < gno; i++) { + double smf = 1.0; + +#ifdef AUTOSM + /* Lookup smoothing factor map */ + if (sm != NULL) { + double p[MXDI]; + double avgdev; + for (e = 0; e < di; e++) + p[e] = gc[e]/(gres[e] - 1.0); + + avgdev = mgtmp_interp(sm, p); + smf = opt_smooth(s, di, s->d.no, avgdev, f); + } +#endif /* AUTOSM */ for (e = 0; e < di; e++) { /* For each curvature direction */ double dw, w0, w1, tt; - double cw = 2.0 * m->sf.cw[e]; /* Overall curvature weight */ - cw *= s->d.vw[f]; /* Scale curvature weight for data range */ + double cw = smf * 2.0 * m->sf.cw[e]; /* Overall curvature weight */ +//printf("~1 cw %f = smf %f * 2 * sd.cw[%d] %f\n",cw,smf,e,m->sf.cw[e]); - /* If at least two above lower edge in this dimension */ /* Add influence on Curvature of cell below */ - if ((gc[e]-2) >= 0) { + if ((gc[e]-2) >= 0 && (gc[e]+0) < gres[e]) { /* double kw = cw * gp[UO_C(e,1)].k; */ /* Cell bellow k value */ double kw = cw; - dw = w1 = 1.0; + w0 = w1 = 1.0; if (m->g.ipos[e] != NULL) { w0 = fabs(m->g.ipos[e][gc[e]-1] - m->g.ipos[e][gc[e]-2]); w1 = fabs(m->g.ipos[e][gc[e]-0] - m->g.ipos[e][gc[e]-1]); //printf("raw [%d][%d] w0 = %f, w1 = %f\n",gc[e],i,w0,w1); -#ifdef EN_DW - dw = 0.5 * (w0 + w1); /* in this direction around -1 */ - dw = dw/dwtw[e]; /* normalise */ -#endif - tt = sqrt(w0 * w1); + tt = 0.5 * (w0 + w1); /* Local full normalisation */ + w0 = tt/w0; w1 = tt/w1; -#ifndef EN_CW - w1 = 1.0; -#endif -//printf("[%d][%d] dw = %f, w1 = %f\n",gc[e],i,dw,w1); +//printf("[%d][%d] w1 = %f\n",gc[e],i,w1); } - A[i][ixcol[0]] += dw * w1 * w1 * kw; - if (ccv != NULL) - b[i] += kw * (w1) * ccv[i - gci[e]][e]; /* Curvature compensation value */ + + A[i][ixcol[0]] += w1 * w1 * kw; +//printf("A[%d][%d] = %f\n",i,0,A[i][ixcol[0]]); } - /* If not one from upper or lower edge in this dimension */ /* Add influence on Curvature of this cell */ if ((gc[e]-1) >= 0 && (gc[e]+1) < gres[e]) { /* double kw = cw * gp->k; */ /* This cells k value */ double kw = cw; - dw = w0 = w1 = 1.0; + w0 = w1 = 1.0; if (m->g.ipos[e] != NULL) { w0 = fabs(m->g.ipos[e][gc[e]-0] - m->g.ipos[e][gc[e]-1]); w1 = fabs(m->g.ipos[e][gc[e]+1] - m->g.ipos[e][gc[e]-0]); //printf("raw [%d][%d] w0 = %f, w1 = %f\n",gc[e],i,w0,w1); -#ifdef EN_DW - dw = 0.5 * (w0 + w1); /* in this direction around 0 */ - dw = dw/dwtw[e]; /* normalise */ -#endif - tt = sqrt(w0 * w1); + tt = 0.5 * (w0 + w1); w0 = tt/w0; w1 = tt/w1; -#ifndef EN_CW - w0 = w1 = 1.0; -#endif -//printf("[%d][%d] dw = %f, w0 = %f, w1 = %f\n",gc[e],i,dw,w0,w1); +//printf("[%d][%d] w0 = %f, w1 = %f\n",gc[e],i,w0,w1); } - A[i][ixcol[0]] += dw * -(w0 + w1) * -(w0 + w1) * kw; - A[i][ixcol[gci[e]]] += dw * -(w0 + w1) * w1 * kw * oawt; - if (ccv != NULL) - b[i] += kw * -(w0 + w1) * ccv[i][e]; /* Curvature compensation value */ + A[i][ixcol[0]] += -(w0 + w1) * -(w0 + w1) * kw; + A[i][ixcol[gci[e]]] += -(w0 + w1) * w1 * kw * oawt; +//printf("A[%d][%d] = %f\n",i,0,A[i][ixcol[0]]); +//printf("A[%d][%d] = %f\n",i,1,A[i][ixcol[gci[e]]]); } - /* If at least two below the upper edge in this dimension */ /* Add influence on Curvature of cell above */ - if ((gc[e]+2) < gres[e]) { + if ((gc[e]+0) >= 0 && (gc[e]+2) < gres[e]) { /* double kw = cw * gp[UO_C(e,2)].k; */ /* Cell above k value */ double kw = cw; - dw = w0 = w1 = 1.0; + w0 = w1 = 1.0; if (m->g.ipos[e] != NULL) { w0 = fabs(m->g.ipos[e][gc[e]+1] - m->g.ipos[e][gc[e]+0]); w1 = fabs(m->g.ipos[e][gc[e]+2] - m->g.ipos[e][gc[e]+1]); //printf("raw [%d][%d] w0 = %f, w1 = %f\n",gc[e],i,w0,w1); -#ifdef EN_DW - dw = 0.5 * (w0 + w1); /* in this direction around +1 */ - dw = dw/dwtw[e]; /* normalise */ -#endif - tt = sqrt(w0 * w1); + tt = 0.5 * (w0 + w1); w0 = tt/w0; w1 = tt/w1; -#ifndef EN_CW - w0 = w1 = 1.0; -#endif -//printf("[%d][%d] dw = %f, w0 = %f, w1 = %f\n",gc[e],i,dw,w0,w1); +//printf("[%d][%d] w0 = %f, w1 = %f\n",gc[e],i,w0,w1); + } + + A[i][ixcol[0]] += w0 * w0 * kw; + A[i][ixcol[1 * gci[e]]] += w0 * -(w0 + w1) * kw; + A[i][ixcol[2 * gci[e]]] += w0 * w1 * kw; +//printf("A[%d][%d] = %f\n",i,0,A[i][ixcol[0]]); +//printf("A[%d][%d] = %f\n",i,1,A[i][ixcol[gci[e]]]); +//printf("A[%d][%d] = %f\n",i,2,A[i][ixcol[2 * gci[e]]]); + } + } + EC_INC(gc); + } + } +#ifdef DEBUG + printf("After adding 2nd order smoothing:\n"); + for (i = 0; i < gno; i++) { + int *xcol = m->q.xcol; + printf("b[%d] = %f\n",i,b[i]); + for (k = acols-1; k > 0; k--) { + if ((i - xcol[k]) >= 0) + printf("A[%d][-%d] = %f\n",i,k,A[i-xcol[k]][k]); + } + for (k = 0; k < acols && (i + xcol[k]) < gno; k++) + printf("A[%d][%d] = %f\n",i,k,A[i][k]); + printf("\n"); + } +#endif /* DEBUG */ + +#ifdef SMOOTH2 + /* Accumulate curvature 2nd order dependent factors to the triangular A matrix. */ + /* Because it's triangular, we compute and add in all the weighting */ + /* factors at and to the right of each cell. */ + + /* The ipos[] factor is to allow for the possibility that the */ + /* grid spacing may be non-uniform in the colorspace where the */ + /* function being modelled is smooth. Our curvature computation */ + /* needs to make allowsance for this fact in computing the */ + /* node value differences that equate to zero curvature. */ + /* + The old curvature fixed grid spacing equation was: + ki * (u[i-1] - 3 * u[i] + 3 * u[i+1] - u[i+2] )^2 + with derivatives wrt each node: + ki-1 * 1 * 2 * eqn(i) + ki * -3 * 2 * eqn(i) + ki+1 * 3 * 2 * eqn(i) + ki+2 * 1 * 2 * eqn(i) + + Allowing for scaling of each grid difference by w[i-1], w[i] and w[i+1], + where w[i-1] corresponds to the width of cell i-1 to i, + and w[i] corresponds to the width of cell i to i+1: + where w[i+1] corresponds to the width of cell i+1 to i+2, + w' = 1/w + + ki * ( w'[i+1] * (u[i+2] - u[i+1]) + - 2 * w'[i] * (u[i+1] - u[i]) + + w'[i-1] * (u[i] - u[i-1]) )^2 + + multiply out to group the node values: + ki * ( w'[i+1] * u[i+2] + - (w'[i+1] + 2 * w'[i]) * u[i+1] + + (2 * w'[i] + w'[i-1]) * u[i] + + w'[i-1] * u[i-1] )^2 + + with derivatives wrt each node: + ~~~ + + */ + + { /* Setting this up from scratch */ + double dwtw[MXDIDO]; /* Density weight normalizer */ + ECOUNT(gc, MXDIDO, di, 0, gres, 0); + EC_INIT(gc); + + /* Compute the ipos[] weight normalisation factors */ + for (e = 0; e < di; e++) { + if (m->g.ipos[e] == NULL) + continue; + dwtw[e] = 0.0; + for (i = 1; i < gres[e]; i++) { + double w; + w = fabs(m->g.ipos[e][i] - m->g.ipos[e][i-1]); +//printf("[%d][%d] w = %f\n",e,i,w); + dwtw[e] += w; + } + dwtw[e] /= (gres[e] - 1.0); /* Average weights */ +//printf("dwtw[%d] = %f\n",e,dwtw[e]); + } + + /* We setup the equation to be solved for each grid point. */ + /* Each grid point participates in foure curvature equations, */ + /* one centered on the grid line below, one that it's the center of, */ + /* one centered on the grid line above, and one centered on the */ + /* grid line two above. The equation setup is for the differential */ + /* for each of these 2nd order curvature equations to be zero. */ + for (i = 0; i < gno; i++) { + double smf = 1.0; + +#ifdef AUTOSM + /* Lookup smoothing factor map */ + if (sm != NULL) { + double p[MXDI]; + double avgdev; + + for (e = 0; e < di; e++) + p[e] = gc[e]/(gres[e] - 1.0); + + avgdev = mgtmp_interp(sm, p); + smf = opt_smooth(s, di, s->d.no, avgdev, f); + } +#endif /* AUTOSM */ + + for (e = 0; e < di; e++) { + double w0, w1, w2, tt; + double cw = smf * 2.0 * m->sf.cw2[e]; /* Overall curvature weight */ +//printf("gno %d dim %d cw %e\n",i,e,cw); + + /* Add influence on Curvature eqation of cell below */ + if ((gc[e]-3) >= 0 && (gc[e]+0) < gres[e]) { + /* double kw = cw * gp[UO_C(e,1)].k; */ /* Cell bellow k value */ + double kw = cw; + w0 = w1 = w2 = 1.0; + if (m->g.ipos[e] != NULL) { + w0 = fabs(m->g.ipos[e][gc[e]-2] - m->g.ipos[e][gc[e]-3]); + w1 = fabs(m->g.ipos[e][gc[e]-1] - m->g.ipos[e][gc[e]-2]); + w2 = fabs(m->g.ipos[e][gc[e]+0] - m->g.ipos[e][gc[e]-1]); + tt = 1.0/3.0 * (w0 + w1 + w2); + w0 = tt/w0; + w1 = tt/w1; + w2 = tt/w2; + } + A[i][ixcol[0]] += w2 * w2 * kw; +//printf("A[%d][%d] = %f\n",i,0,A[i][ixcol[0]]); + } + /* Add influence on Curvature of this cell */ + if ((gc[e]-2) >= 0 && (gc[e]+1) < gres[e]) { + /* double kw = cw * gp->k; */ /* This cells k value */ + double kw = cw; + w0 = w1 = w2 = 1.0; + if (m->g.ipos[e] != NULL) { + w0 = fabs(m->g.ipos[e][gc[e]-1] - m->g.ipos[e][gc[e]-2]); + w1 = fabs(m->g.ipos[e][gc[e]+0] - m->g.ipos[e][gc[e]-1]); + w2 = fabs(m->g.ipos[e][gc[e]+1] - m->g.ipos[e][gc[e]+0]); + tt = 1.0/3.0 * (w0 + w1 + w2); + w0 = tt/w0; + w1 = tt/w1; + w2 = tt/w2; + } + A[i][ixcol[0]] += -(2.0 * w1 + w2) * -(2.0 * w1 + w2) * kw; + A[i][ixcol[gci[e]]] += -(2.0 * w1 + w2) * w2 * kw; +//printf("A[%d][%d] = %f\n",i,0,A[i][ixcol[0]]); +//printf("A[%d][%d] = %f\n",i,1,A[i][ixcol[gci[e]]]); + } + /* Add influence on Curvature of cell above */ + if ((gc[e]-1) >= 0 && (gc[e]+2) < gres[e]) { + /* double kw = cw * gp[UO_C(e,2)].k; */ /* Cell above k value */ + double kw = cw; + w0 = w1 = w2 = 1.0; + if (m->g.ipos[e] != NULL) { + w0 = fabs(m->g.ipos[e][gc[e]+0] - m->g.ipos[e][gc[e]-1]); + w1 = fabs(m->g.ipos[e][gc[e]+1] - m->g.ipos[e][gc[e]+0]); + w2 = fabs(m->g.ipos[e][gc[e]+2] - m->g.ipos[e][gc[e]+1]); + tt = 1.0/3.0 * (w0 + w1 + w2); + w0 = tt/w0; + w1 = tt/w1; + w2 = tt/w2; } - A[i][ixcol[0]] += dw * w0 * w0 * kw; - A[i][ixcol[gci[e]]] += dw * w0 * -(w0 + w1) * kw; - A[i][ixcol[2 * gci[e]]] += dw * w0 * w1 * kw; - if (ccv != NULL) - b[i] += kw * -(w0 + w1) * ccv[i][e]; /* Curvature compensation value */ + A[i][ixcol[0]] += (w0 + 2.0 * w1) * (w0 + 2.0 * w1) * kw; + A[i][ixcol[1 * gci[e]]] += (w0 + 2.0 * w1) * -(2.0 * w1 + w2) * kw; + A[i][ixcol[2 * gci[e]]] += (w0 + 2.0 * w1) * w2 * kw * oawt; +//printf("A[%d][%d] = %f\n",i,0,A[i][ixcol[0]]); +//printf("A[%d][%d] = %f\n",i,1,A[i][ixcol[gci[e]]]); +//printf("A[%d][%d] = %f\n",i,2,A[i][ixcol[2 * gci[e]]]); + } + /* Add influence on Curvature of cell two above */ + if ((gc[e]+0) >= 0 && (gc[e]+3) < gres[e]) { + /* double kw = cw * gp[UO_C(e,3)].k; */ /* Cell two above k value */ + double kw = cw; + w0 = w1 = w2 = 1.0; + if (m->g.ipos[e] != NULL) { + w0 = fabs(m->g.ipos[e][gc[e]+1] - m->g.ipos[e][gc[e]+0]); + w1 = fabs(m->g.ipos[e][gc[e]+2] - m->g.ipos[e][gc[e]+1]); + w2 = fabs(m->g.ipos[e][gc[e]+3] - m->g.ipos[e][gc[e]+2]); + tt = 1.0/3.0 * (w0 + w1 + w2); + w0 = tt/w0; + w1 = tt/w1; + w2 = tt/w2; + } + A[i][ixcol[0]] += -w0 * -w0 * kw; + A[i][ixcol[1 * gci[e]]] += -w0 * (w0 + 2.0 * w1) * kw; + A[i][ixcol[2 * gci[e]]] += -w0 * -(2.0 * w1 + w2) * kw; + A[i][ixcol[3 * gci[e]]] += -w0 * w2 * kw; +//printf("A[%d][%d] = %f\n",i,0,A[i][ixcol[0]]); +//printf("A[%d][%d] = %f\n",i,1,A[i][ixcol[gci[e]]]); +//printf("A[%d][%d] = %f\n",i,2,A[i][ixcol[2 * gci[e]]]); +//printf("A[%d][%d] = %f\n",i,3,A[i][ixcol[3 * gci[e]]]); } } EC_INC(gc); } } +#ifdef DEBUG + printf("After adding 3rd order smoothing:\n"); + for (i = 0; i < gno; i++) { + int *xcol = m->q.xcol; + printf("b[%d] = %f\n",i,b[i]); + for (k = acols-1; k > 0; k--) { + if ((i - xcol[k]) >= 0) + printf("A[%d][-%d] = %f\n",i,k,A[i-xcol[k]][k]); + } + for (k = 0; k < acols && (i + xcol[k]) < gno; k++) + printf("A[%d][%d] = %f\n",i,k,A[i][k]); + printf("\n"); + } +#endif /* DEBUG */ #ifdef DEBUG - printf("After adding curvature equations:\n"); + printf("After adding 2nd and 3rd order smoothing equations:\n"); for (i = 0; i < gno; i++) { printf("b[%d] = %f\n",i,b[i]); for (k = 0; k < acols; k++) { @@ -1642,6 +2214,7 @@ static void setup_solve( printf("\n"); } #endif /* DEBUG */ +#endif /* SMOOTH2 */ nbsum = 0.0; /* Zero sum of b[] squared */ @@ -1649,7 +2222,7 @@ static void setup_solve( /* weak "data point" exactly at each grid point. */ /* (Note we're not currently doing this in a cache friendly order, */ /* and we're calling the function once for each output component..) */ - if (s->dfunc != NULL) { /* Setting this up from scratch */ + if (s->dfunc != NULL && f >= 0) { /* Setting this up from scratch */ double iv[MXDI], ov[MXDO]; ECOUNT(gc, MXDIDO, di, 0, gres, 0); EC_INIT(gc); @@ -1681,7 +2254,6 @@ static void setup_solve( printf("\n"); } #endif /* DEBUG */ - } /* Accumulate data point dependent factors */ @@ -1698,8 +2270,8 @@ static void setup_solve( ai = bp + m->g.hi[j]; /* A matrix index */ w = m->d[n].w[j]; /* Base point grid weight */ - d = 2.0 * s->d.a[n].k[f] * w; /* (2.0, w are derivative factors, k data pnt wgt) */ - tt = d * s->d.a[n].cv[f]; /* Change in (corrected) data component */ + d = 2.0 * s->d.a[n].k[f] * w; /* (2.0, w are derivtv factors, k data pnt wgt) */ + tt = d * s->d.a[n].v[f]; /* Change in data component */ nbsum += (2.0 * b[ai] + tt) * tt; /* += (b[ai] + tt)^2 - b[ai]^2 */ b[ai] += tt; /* New data component value */ @@ -1735,300 +2307,18 @@ static void setup_solve( // exit(0); } +#ifdef AUTOSM -/* Given that we've done a complete fit at the current resolution, */ -/* allocate and compute the curvature error of each grid point and put it in */ -/* s->g.ccv[gno][di] */ -static void comp_ccv( - mgtmp *m /* Solution to use */ -) { - rspl *s = m->s; - int gno = m->g.no, *gres = m->g.res, *gci = m->g.ci; - int di = s->di; - double *x = m->q.x; /* Grid solution values */ - int f = m->f; /* Output dimensions being worked on */ - int e, i; - - ECOUNT(gc, MXDIDO, di, 0, gres, 0); - EC_INIT(gc); - - if (s->g.ccv == NULL) { - if ((s->g.ccv = dmatrixz(0, gno-1, 0, di-1)) == NULL) { - error("Malloc of ccv[] failed with [%d][%d]",di,gno); - } - } - - for (i = 0; i < gno; i++) { - for (e = 0; e < di; e++) { /* For each curvature direction */ - double w0, w1, tt; - - s->g.ccv[i][e] = 0.0; /* Default value */ - - /* If not one from upper or lower edge in this dimension */ - if ((gc[e]-1) >= 0 && (gc[e]+1) < gres[e]) { - /* double kw = cw * gp->k; */ /* This cells k value */ - w0 = w1 = 1.0; - if (m->g.ipos[e] != NULL) { - w0 = fabs(m->g.ipos[e][gc[e]-0] - m->g.ipos[e][gc[e]-1]); - w1 = fabs(m->g.ipos[e][gc[e]+1] - m->g.ipos[e][gc[e]-0]); - tt = sqrt(w0 * w1); - w0 = tt/w0; - w1 = tt/w1; - } - s->g.ccv[i][e] += w0 * x[i - gci[e]]; - s->g.ccv[i][e] += -(w0 + w1) * x[i]; - s->g.ccv[i][e] += w1 * x[i + gci[e]]; - } -//printf("~1 computing ccv for node %d is %f\n",i,s->g.ccv[i][0]); - } - EC_INC(gc); - } -} - -/* Down sample the curvature compensation values in s->g.ccv to */ -/* a given solution. Allocate the m->q.ccv if necessary. */ -static void init_ccv( - mgtmp *m /* Destination */ -) { - rspl *s = m->s; - int f = m->f; /* Output dimensions being worked on */ - int di = s->di; - int gno = m->g.no; - int gres1_1[MXDI]; /* Destination */ - int gres2_1[MXDI]; /* Source */ - double scale[MXDI]; /* ccv scale factor */ - int e, n; - ECOUNT(gc, MXDIDO, di, 0, m->g.res, 0); /* Counter for output points */ - - for (e = 0; e < di; e++) { - gres1_1[e] = m->g.res[e]-1; - gres2_1[e] = s->g.res[e]-1; - } - - if (m->q.ccv == NULL) { - if ((m->q.ccv = dmatrixz(0, gno-1, 0, di-1)) == NULL) { - error("Malloc of ccv[] failed with [%d][%d]",di,gno); - } - } - - /* Compute the scale factor to compensate for the grid resolution */ - /* effect on the grid difference values. */ - for (e = 0; e < di; e++) { - double rsm_s, rsm_d; - - if (s->symdom) { /* Relative final grid size */ - rsm_s = s->g.res[e]; - rsm_d = m->g.res[e]; - } else { /* Relative mean final grid size */ - rsm_s = s->g.mres; - rsm_d = m->g.mres; - } - - rsm_s = pow((rsm_s-1.0), 2.0); /* Geometric resolution factor for smooth surfaces */ - rsm_d = pow((rsm_d-1.0), 2.0); /* (It's ^2 rather than ^4 as it's is before squaring) */ - - scale[e] = rsm_s/rsm_d; - } - - /* Point sampling is probably not the ideal way of down sampling, */ - /* but it's easy, and won't be too bad if the s->g.ccv has been */ - /* low pass filtered. */ - - /* For all grid ccv's */ - EC_INIT(gc); - for (n = 0; n < gno; n++) { - double we[MXRI]; /* 1.0 - Weight in each dimension */ - double gw[POW2MXRI]; /* weight for each grid cube corner */ - int ix; /* Index of source ccv grid cube base */ - - /* Figure out which grid cell the point falls into */ - { - double t; - int mi; - ix = 0; - for (e = 0; e < di; e++) { - t = ((double)gc[e]/(double)gres1_1[e]) * (double)gres2_1[e]; - mi = (int)floor(t); /* Grid coordinate */ - if (mi < 0) /* Limit to valid cube base index range */ - mi = 0; - else if (mi >= gres2_1[e]) - mi = gres2_1[e]-1; - ix += mi * s->g.ci[e]; /* Add Index offset for grid cube base in dimen */ - we[e] = t - (double)mi; /* 1.0 - weight */ - } - } - - /* Compute corner weights needed for interpolation */ - { - int i, g; - gw[0] = 1.0; - for (e = 0, g = 1; e < di; g *= 2, e++) { - for (i = 0; i < g; i++) { - gw[g+i] = gw[i] * we[e]; - gw[i] *= (1.0 - we[e]); - } - } - } - - /* Compute the output values */ - { - int i; - for (e = 0; e < di; e++) - m->q.ccv[n][e] = 0.0; /* Zero output value */ - for (i = 0; i < (1 << di); i++) { /* For all corners of cube */ - int oix = ix + s->g.hi[i]; - for (e = 0; e < di; e++) - m->q.ccv[n][e] += gw[i] * s->g.ccv[oix][e]; - } - /* Rescale curvature for grid spacing */ - for (e = 0; e < di; e++) - m->q.ccv[n][e] *= scale[e]; -//printf("~1 downsampling ccv for node %d is %f\n",n,m->q.ccv[n][0]); - } - EC_INC(gc); - } -} - -/* Apply a gaussian filter to the curvature compensation values */ -/* s->g.ccv[gno][di], to apply smoothing. */ -static void filter_ccv( - rspl *s, - double stdev /* Standard deviation diameter of filter (in input) */ - /* 1.0 = grid width */ -) { - int k, e, ee, i, j, di = s->di; - int gno = s->g.no, *gres = s->g.res, *gci = s->g.ci; - double *_fkern[MXDI], *fkern[MXDI]; /* Filter kernels */ - int kmin[MXDI], kmax[MXDI]; /* Kernel index range (inclusive) */ - double *_row, *row; /* Extended copy of each row processed */ - -//printf("Doing filter stdev %f\n",stdev); - -//printf("~1 bres = %d, index %d to %d\n",s->g.bres,-s->g.bres+1,s->g.bres+s->g.bres-1); - if ((_row = (double *) malloc(sizeof(double) * (s->g.bres * 3 - 2))) == NULL) - error("rspl malloc failed - ccv row copy"); - row = _row + s->g.bres-1; /* Allow +/- gres-1 */ - - /* Compute the kernel weightings for the given stdev */ - for (ee = 0; ee < di; ee++) { /* For each dimension direction */ - int cres; /* Current res */ - double k1, k2, tot; - -//printf("Filter along dim %d:\n",ee); - if ((_fkern[ee] = (double *) malloc(sizeof(double) * (gres[ee] * 2 - 1))) == NULL) - error("rspl malloc failed - ccv filter kernel"); - fkern[ee] = _fkern[ee] + gres[ee]-1; /* node of interest at center */ - - /* Take gaussian constants out of the loop */ - k2 = 1.0 / (2.0 * pow(fabs(stdev), TWOPASSORDER)); - k1 = k2 / 3.1415926; - - /* Comute the range needed */ - if (s->symdom) { - cres = gres[ee]; - } else { - cres = s->g.mres; - } - kmin[ee] = (int)floor(-5.0 * stdev * (cres-1.0)); - kmax[ee] = (int)ceil(5.0 * stdev * (cres-1.0)); - - if (kmin[ee] < (-gres[ee]+1)) - kmin[ee] = -gres[ee]+1; - else if (kmin[ee] > -1) - kmin[ee] = -1; - if (kmax[ee] > (gres[ee]-1)) - kmax[ee] = gres[ee]-1; - else if (kmax[ee] < 1) - kmax[ee] = 1; -//printf("kmin = %d, kmax = %d\n",kmin[ee], kmax[ee]); - - for (tot = 0.0, i = kmin[ee]; i <= kmax[ee]; i++) { - double fi = (double)i; - - /* Do a discrete integration of the gassian function */ - /* to compute discrete weightings */ - fkern[ee][i] = 0.0; - for (k = -4; k < 5; k++) { - double oset = (fi + k/9.0)/(cres-1.0); - double val; - - val = k1 * exp(-k2 * pow(fabs(oset), TWOPASSORDER)); - fkern[ee][i] += val; - tot += val; - } - } - /* Normalize the sum */ - for (tot = 1.0/tot, i = kmin[ee]; i <= kmax[ee]; i++) - fkern[ee][i] *= tot; -//printf("Filter cooefs:\n"); -//for (i = kmin[ee]; i <= kmax[ee]; i++) -//printf("%d: %e\n",i,fkern[ee][i]); - } - - for (k = 0; k < di; k++) { /* For each curvature direction */ - for (ee = 0; ee < di; ee++) { /* For each dimension direction */ - int tgres[MXDI-1]; - -//printf("~1 Filtering curv dir %d, dim dir %d\n",k,ee); - /* Setup counters for scanning through all other dimensions */ - for (j = e = 0; e < di; e++) { - if (e == ee) - continue; - tgres[j++] = gres[e]; - } - /* For each row of this dimension */ - { - ECOUNT(gc, MXDIDO-1, di-1, 0, tgres, 0); /* Count other dimensions */ - - EC_INIT(gc); - for (; di <= 1 || !EC_DONE(gc);) { - int ix; - - /* Compute index of start of row */ - for (ix = j = e = 0; e < di; e++) { - if (e == ee) - continue; - ix += gc[j++] * gci[e]; - } +~~~~9999 - /* Copy row to temporary array, and expand */ - /* edge values by mirroring them. */ - for (i = 0; i < gres[ee]; i++) - row[i] = s->g.ccv[ix + i * gci[ee]][k]; - for (i = kmin[ee]; i < 0; i++) - row[i] = 2.0 * row[0] - row[-i]; /* Mirror the value */ - for (i = gres[ee]-1 + kmax[ee]; i > (gres[ee]-1); i--) - row[i] = 2.0 * row[gres[ee]-1] - row[gres[ee]-1-i]; /* Mirror the value */ -//printf("~1 Row = \n"); -//for (i = kmin[ee]; i <= (gres[ee]-1 + kmax[ee]); i++) -//printf("%d: %f\n",i,row[i]); - - /* Apply the 1D convolution to the temporary array */ - /* to produce the filtered values. */ - for (i = 0; i < gres[ee]; i++) { - double fv; - - for (fv = 0.0, j = kmin[ee]; j <= kmax[ee]; j++) - fv += fkern[ee][j] * row[i + j]; - s->g.ccv[ix + i * gci[ee]][k] = fv; - } - if (di <= 1) - break; - EC_INC(gc); - } - } - } - } +#endif - for (ee = 0; ee < di; ee++) - free(_fkern[ee] ); - free(_row); -} +#ifdef AUTOSM /* Given that we've done a complete fit at the current resolution, */ -/* compute the error of each data point, and then compute */ -/* a correction factor .cv[] for each point from this. */ -static void comp_extrafit_corr( +/* compute the error of each data point. */ +/* This is used to compute a smoothness factor map */ +static void comp_fit_errors( mgtmp *m /* Current resolution mgtmp */ ) { rspl *s = m->s; @@ -2037,6 +2327,7 @@ static void comp_extrafit_corr( int di = s->di; double *x = m->q.x; /* Grid solution values */ int f = m->f; /* Output dimensions being worked on */ + double fea = 0.0; /* Average value */ /* Compute error for each data point */ for (n = 0; n < dno; n++) { @@ -2047,34 +2338,74 @@ static void comp_extrafit_corr( double gain = 1.0; /* Compute the interpolated grid value for this data point */ - for (val = 0.0, j = 0; j < (1 << di); j++) { /* Binary sequence */ + for (val = 0.0, j = 0; j < (1 << di); j++) /* Binary sequence */ val += m->d[n].w[j] * x[bp + m->g.hi[j]]; - } err = s->d.a[n].v[f] - val; + err *= 0.8; +// s->d.a[n].fe = fabs(err); +//printf("~1 data %d fe = %f\n",n,s->d.a[n].fe); + fea += s->d.a[n].fe; + } + fea /= (double)dno; -#ifdef NEVER - /* Compute gain from previous move */ - if (fabs(s->d.a[n].pe[f]) > 0.001) { - gain = (val - s->d.a[n].pv[f])/s->d.a[n].pe[f]; - if (gain < 0.2) - gain = 0.2; - else if (gain > 5.0) - gain = 5.0; - gain = pow(gain, 0.6); - } else { - gain = 1.0; +// s->d.fea = fea; /* Average fit error */ +} + +#endif /* AUTOSM */ + +/* Return an interpolayed value */ +static double mgtmp_interp( + mgtmp *m, + double p[MXDI] /* Input coord in normalised grid forms */ +) { + rspl *s = m->s; + int di = s->di; + int e, n; + double we[MXRI]; /* 1.0 - Weight in each dimension */ + double gw[POW2MXRI]; /* weight for each grid cube corner */ + double *gp; /* Pointer to x2[] grid cube base */ + double val; + + /* Figure out which grid cell the point falls into */ + { + double t; + int mi; + gp = m->q.x; /* Base of solution array */ + for (e = 0; e < di; e++) { + t = (double)p[e] * (m->g.res[e] - 1.0); + mi = (int)floor(t); /* Grid coordinate */ + if (mi < 0) /* Limit to valid cube base index range */ + mi = 0; + else if (mi >= (m->g.res[e] - 1)) + mi = m->g.res[e] - 2; + gp += mi * m->g.ci[e]; /* Add Index offset for grid cube base in dimen */ + we[e] = t - (double)mi; /* 1.0 - weight */ } -#endif - /* Correct the target data point value by the error */ - s->d.a[n].cv[f] += err / gain; - -//printf("~1 Data point %d, v = %f, cv = %f, change = %f\n",n,s->d.a[n].v[f],s->d.a[n].cv[f],-val); -//printf("~1 Data point %d, pe = %f, change = %f, gain = %f\n",n,s->d.a[n].pe[f],val - s->d.a[n].pv[f],gain); -//printf("~1 Data point %d err = %f, target %f, was %f, now %f\n",n,err,s->d.a[n].v[f],val,s->d.a[n].cv[f]); -// s->d.a[n].pe[f] = err / gain; -// s->d.a[n].pv[f] = val; } + + /* Compute corner weights needed for interpolation */ + { + int i, g; + gw[0] = 1.0; + for (e = 0, g = 1; e < di; g *= 2, e++) { + for (i = 0; i < g; i++) { + gw[g+i] = gw[i] * we[e]; + gw[i] *= (1.0 - we[e]); + } + } + } + + /* Compute the output values */ + { + int i; + val = 0.0; /* Zero output value */ + for (i = 0; i < (1 << di); i++) { /* For all corners of cube */ + val += gw[i] * gp[m->g.hi[i]]; + } + } + + return val; } /* Transfer a solution from one mgtmp to another */ @@ -2086,64 +2417,48 @@ static void init_soln( rspl *s = m1->s; int di = s->di; int gno = m1->g.no; - int gres1_1[MXDI]; - int gres2_1[MXDI]; int e, n; ECOUNT(gc, MXDIDO, di, 0, m1->g.res, 0); /* Counter for output points */ - for (e = 0; e < di; e++) { - gres1_1[e] = m1->g.res[e]-1; - gres2_1[e] = m2->g.res[e]-1; - } - /* For all output grid points */ EC_INIT(gc); for (n = 0; n < gno; n++) { - double we[MXRI]; /* 1.0 - Weight in each dimension */ - double gw[POW2MXRI]; /* weight for each grid cube corner */ - double *gp; /* Pointer to x2[] grid cube base */ - - /* Figure out which grid cell the point falls into */ - { - double t; - int mi; - gp = m2->q.x; /* Base of solution array */ - for (e = 0; e < di; e++) { - t = ((double)gc[e]/(double)gres1_1[e]) * (double)gres2_1[e]; - mi = (int)floor(t); /* Grid coordinate */ - if (mi < 0) /* Limit to valid cube base index range */ - mi = 0; - else if (mi >= gres2_1[e]) - mi = gres2_1[e]-1; - gp += mi * m2->g.ci[e]; /* Add Index offset for grid cube base in dimen */ - we[e] = t - (double)mi; /* 1.0 - weight */ - } - } + double p[MXRI]; /* Grid relative location */ - /* Compute corner weights needed for interpolation */ - { - int i, g; - gw[0] = 1.0; - for (e = 0, g = 1; e < di; g *= 2, e++) { - for (i = 0; i < g; i++) { - gw[g+i] = gw[i] * we[e]; - gw[i] *= (1.0 - we[e]); - } - } - } + for (e = 0; e < di; e++) + p[e] = (double)gc[e]/(m1->g.res[e] - 1.0); + + m1->q.x[n] = mgtmp_interp(m2, p); - /* Compute the output values */ - { - int i; - m1->q.x[n] = 0.0; /* Zero output value */ - for (i = 0; i < (1 << di); i++) { /* For all corners of cube */ - m1->q.x[n] += gw[i] * gp[m2->g.hi[i]]; - } - } EC_INC(gc); } } + +#ifdef AUTOSM + +#ifndef NEVER // Debug + +/* Plot the 0'th dimension response */ +void plot_mgtmp1(mgtmp *m) { + int i; + double xx[100]; + double yy[100]; + double p[MXDI]; + + for (i = 0; i < m->s->di; i++) + p[i] = 0.0; + + for (i = 0; i < 100; i++) { + xx[i] = p[0] = (double)i/99.0; + yy[i] = mgtmp_interp(m, p); + } + do_plot(xx, yy, NULL, NULL, 100); +} + +#endif /* NEVER */ +#endif /* AUTOSM */ + /* - - - - - - - - - - - - - - - - - - - -*/ static double one_itter1(cj_arrays *ta, double **A, double *x, double *b, double normb, @@ -2234,7 +2549,7 @@ solve_gres(mgtmp *m, cj_arrays *ta, double tol, int final) /* Note that we process the A[][] sparse columns in compact form */ #ifdef DEBUG_PROGRESS - printf("Target tol = %f\n",tol); + printf("Target tol = %e\n",tol); #endif /* If the number of point is small, or it is just one */ /* dimensional, solve it more directly. */ @@ -2417,7 +2732,7 @@ one_itter2( sm += A[i][k] * x[k3]; /* Left of diagonal in 4's */ - /* (We take advantage of the symetry: what would be in the row */ + /* (We take advantage of A[][] symetry: what would be in the row */ /* to the left is repeated in the column above.) */ for (k = 1, k3 = i-xcol[k+3]; (k+3) < acols && k3 >= 0; k += 4, k3 = i-xcol[k+3]) { k0 = i-xcol[k+0]; @@ -2432,6 +2747,7 @@ one_itter2( for (k3 = i-xcol[k]; k < acols && k3 >= 0; k++, k3 = i-xcol[k]) sm += A[k3][k] * x[k3]; + /* Compute x value that solves equation just for this point */ // x[i] = (b[i] - sm)/A[i][0]; x[i] += ovsh * ((b[i] - sm)/A[i][0] - x[i]); @@ -2627,8 +2943,10 @@ cj_line( sm += A[ii][k] * x[k3]; /* Left of diagonal in 4's */ - /* (We take advantage of the symetry: what would be in the row */ - /* to the left is repeated in the column above.) */ + /* (We take advantage of the symetry around the diagonal: what would be in the row */ + /* to the left is repeated in the column above, so for an unsparse matrix */ + /* we simply swapt the row and column index, for sparse we use the mirror column */ + /* offset (ie. to the right side) and subtract the column offset from the row.) */ for (k = 1, k3 = ii-xcol[k+3]; (k+3) < acols && k3 >= 0; k += 4, k3 = ii-xcol[k+3]) { k0 = ii-xcol[k+0]; k1 = ii-xcol[k+1]; @@ -2682,6 +3000,7 @@ cj_line( max_it = 0; } + /* Improve the solution */ for (it = 1; it <= max_it; it++) { /* Aproximately solve for z[] given r[], */ -- cgit v1.2.3