2
/***********************************************************************
4
* MODULE: v.surf.bspline
6
* AUTHOR(S): Roberto Antolin
8
* PURPOSE: Spline Interpolation and cross correlation
10
* COPYRIGHT: (C) 2006 by Politecnico di Milano -
11
* Polo Regionale di Como
13
* This program is free software under the
14
* GNU General Public License (>=v2).
15
* Read the file COPYING that comes with GRASS
18
**************************************************************************/
24
#include <grass/gis.h>
25
#include <grass/Vect.h>
26
#include <grass/dbmi.h>
27
#include <grass/glocale.h>
28
#include <grass/config.h>
29
#include <grass/PolimiFunct.h>
32
#define PARAM_LAMBDA 6
33
#define PARAM_SPLINE 0
34
#define SWAP(a, b) {double t=a; a=b; b=t;}
36
/*-------------------------------------------------------------------------------------------*/
37
int cross_correlation(struct Map_info *Map, double passWE, double passNS)
39
Map: Vector map from which cross-crorrelation will take values
40
passWE: spline step in West-East direction
41
passNS: spline step in North-South direction
48
int bilin = TRUE; /*booleans */
49
int nsplx, nsply, nparam_spl, ndata;
50
double *mean, *rms, *stdev, rms_min, stdev_min;
52
/* double lambda[PARAM_LAMBDA] = { 0.0001, 0.001, 0.01, 0.1, 1.0, 10.0 }; */ /* Fixed values (at the moment) */
53
double lambda[PARAM_LAMBDA] = { 0.01, 0.05, 0.1, 0.2, 0.3, 0.4 }; /* Fixed values (at the moment) */
54
/* a more exhaustive search:
55
#define PARAM_LAMBDA 11
56
double lambda[PARAM_LAMBDA] = { 0.0001, 0.0005, 0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1.0, 5.0, 10.0 }; */
58
double *TN, *Q, *parVect; /* Interpolation and least-square vectors */
59
double **N, **obsVect; /* Interpolation and least-square matrix */
62
struct Stats stat_vect;
64
/*struct line_pnts *points; */
65
/*struct line_cats *Cats; */
66
struct Cell_head region;
68
G_get_window(®ion);
70
extern int bspline_field;
71
extern char *bspline_column;
75
"CrossCorrelation: Some tests using different lambda_i values will be done");
77
ndata = Vect_get_num_lines(Map);
79
if (ndata > NDATA_MAX)
80
G_warning(_("%d are too many points. "
81
"The cross validation would take too much time."), ndata);
83
/*points = Vect_new_line_struct (); */
84
/*Cats = Vect_new_cats_struct (); */
86
/* Current region is read and points recorded into observ */
87
observ = P_Read_Vector_Region_Map(Map, ®ion, &ndata, 1024, 1);
88
G_debug(5, "CrossCorrelation: %d points read in region. ", ndata);
89
G_verbose_message(_("%d points read in region"),
93
G_warning(_("Maybe, it takes too long. "
94
"It will depend on how many points you are considering."));
96
G_debug(5, "CrossCorrelation: It shouldn't take too long.");
98
if (ndata > 0) { /* If at least one point is in the region */
99
int i, j, lbd; /* lbd: lambda index */
100
int BW, lbd_min; /* lbd_min: index where minimun is found */
101
double mean_reg, *obs_mean;
103
int nrec, ctype = 0, verbosity;
104
struct field_info *Fi;
105
dbDriver *driver_cats;
107
mean = G_alloc_vector(PARAM_LAMBDA); /* Alloc as much mean, rms and stdev values as the total */
108
rms = G_alloc_vector(PARAM_LAMBDA); /* number of parameter used used for cross validation */
109
stdev = G_alloc_vector(PARAM_LAMBDA);
111
verbosity = G_verbose(); /* store for later reset */
113
/* Working with attributes */
114
if (bspline_field > 0) {
115
db_CatValArray_init(&cvarr);
117
Fi = Vect_get_field(Map, bspline_field);
119
G_fatal_error(_("Database connection not defined for layer %d"),
123
db_start_driver_open_database(Fi->driver, Fi->database);
124
G_debug(1, _("CrossCorrelation: driver=%s db=%s"), Fi->driver,
127
if (driver_cats == NULL)
128
G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
129
Fi->database, Fi->driver);
132
db_select_CatValArray(driver_cats, Fi->table, Fi->key,
133
bspline_column, NULL, &cvarr);
134
G_debug(3, "nrec = %d", nrec);
137
if (ctype != DB_C_TYPE_INT && ctype != DB_C_TYPE_DOUBLE)
138
G_fatal_error(_("Column type not supported"));
141
G_fatal_error(_("No records selected from table <%s> "),
144
G_debug(1, "%d records selected from table",
147
db_close_database_shutdown_driver(driver_cats);
150
/* Setting number of splines as a function of WE and SN spline steps */
151
nsplx = ceil((region.east - region.west) / passWE);
152
nsply = ceil((region.north - region.south) / passNS);
153
nparam_spl = nsplx * nsply; /* Total number of splines */
155
if (nparam_spl > 22900)
156
G_fatal_error(_("Too many splines (%d x %d). "
157
"Consider changing spline steps \"sie=\" \"sin=\"."),
160
BW = P_get_BandWidth(bilin, nsply);
162
/*Least Squares system */
163
N = G_alloc_matrix(nparam_spl, BW); /* Normal matrix */
164
TN = G_alloc_vector(nparam_spl); /* vector */
165
parVect = G_alloc_vector(nparam_spl); /* Parameters vector */
166
obsVect = G_alloc_matrix(ndata, 3); /* Observation vector */
167
Q = G_alloc_vector(ndata); /* "a priori" var-cov matrix */
169
obs_mean = G_alloc_vector(ndata);
170
stat_vect = alloc_Stats(ndata);
172
for (lbd = 0; lbd < PARAM_LAMBDA; lbd++) { /* For each lambda value */
174
G_message(_("Beginning cross validation with "
175
"lambda_i=%.4f ... (%d of %d)"), lambda[lbd],
176
lbd+1, PARAM_LAMBDA);
179
How the cross correlation algorithm is done:
180
For each cycle, only the first ndata-1 "observ" elements are considered for the
181
interpolation. Within every interpolation mean is calculated to lowering border
182
errors. The point left out will be used for an estimation. The error between the
183
estimation and the observation is recorded for further statistics.
184
At the end of the cycle, the last point, that is, the ndata-1 index, and the point
185
with j index are swapped.
187
for (j = 0; j < ndata; j++) { /* Cross Correlation will use all ndata points */
188
double out_x, out_y, out_z; /* This point is left out */
190
for (i = 0; i < ndata; i++) { /* Each time, only the first ndata-1 points */
191
double dval; /* are considered in the interpolation */
193
/* Setting obsVect vector & Q matrix */
195
obsVect[i][0] = observ[i].coordX;
196
obsVect[i][1] = observ[i].coordY;
198
if (bspline_field > 0) {
201
/*type = Vect_read_line (Map, points, Cats, observ[i].lineID); */
202
/*if ( !(type & GV_POINTS ) ) continue; */
204
/*Vect_cat_get ( Cats, bspline_field, &cat ); */
210
if (ctype == DB_C_TYPE_INT) {
212
db_CatValArray_get_value_int(&cvarr, cat,
214
obsVect[i][2] = ival;
217
else { /* DB_C_TYPE_DOUBLE */
219
db_CatValArray_get_value_double(&cvarr, cat,
221
obsVect[i][2] = dval;
225
G_warning(_("No record for point (cat = %d)"),
231
obsVect[i][2] = observ[i].coordZ;
232
obs_mean[i] = observ[i].coordZ;
236
/* Mean calculation for every point less the last one */
237
mean_reg = calc_mean(obs_mean, ndata - 1);
239
for (i = 0; i < ndata; i++)
240
obsVect[i][2] -= mean_reg;
242
/* This is left out */
243
out_x = observ[ndata - 1].coordX;
244
out_y = observ[ndata - 1].coordY;
245
out_z = obsVect[ndata - 1][2];
247
if (bilin) { /* Bilinear interpolation */
248
normalDefBilin(N, TN, Q, obsVect, passWE, passNS, nsplx,
249
nsply, region.west, region.south,
250
ndata - 1, nparam_spl, BW);
251
nCorrectGrad(N, lambda[lbd], nsplx, nsply, passWE,
254
else { /* Bicubic interpolation */
255
normalDefBicubic(N, TN, Q, obsVect, passWE, passNS, nsplx,
256
nsply, region.west, region.south,
257
ndata - 1, nparam_spl, BW);
258
nCorrectGrad(N, lambda[lbd], nsplx, nsply, passWE,
263
if (bilin) interpolation (&interp, P_BILINEAR);
264
else interpolation (&interp, P_BICUBIC);
266
G_set_verbose(G_verbose_min());
267
tcholSolve(N, TN, parVect, nparam_spl, BW);
268
G_set_verbose(verbosity);
270
/* Estimation of j-point */
272
stat_vect.estima[j] =
273
dataInterpolateBilin(out_x, out_y, passWE, passNS,
274
nsplx, nsply, region.west,
275
region.south, parVect);
278
stat_vect.estima[j] =
279
dataInterpolateBilin(out_x, out_y, passWE, passNS,
280
nsplx, nsply, region.west,
281
region.south, parVect);
283
/* Difference between estimated and observated i-point */
284
stat_vect.error[j] = out_z - stat_vect.estima[j];
285
G_debug(1, "CrossCorrelation: stat_vect.error[%d] = %lf", j,
288
/* Once the last value is left out, it is swaped with j-value */
289
observ = swap(observ, j, ndata - 1);
291
G_percent(j, ndata, 2);
294
mean[lbd] = calc_mean(stat_vect.error, stat_vect.n_points);
296
calc_root_mean_square(stat_vect.error, stat_vect.n_points);
298
calc_standard_deviation(stat_vect.error, stat_vect.n_points);
300
G_message(_("Mean = %.5lf"), mean[lbd]);
301
G_message(_("Root Mean Square (RMS) = %.5lf"),
304
} /* ENDFOR each lambda value */
309
G_free_matrix(obsVect);
310
G_free_vector(parVect);
312
/*TODO: if the minimum lambda is wanted, the function declaration must be changed */
313
/* At this moment, consider rms only */
314
rms_min = find_minimum(rms, &lbd_min);
315
stdev_min = find_minimum(stdev, &lbd_min);
317
/* Writing some output */
318
G_message(_("Different number of splines and lambda_i values have "
319
"been taken for the cross correlation"));
320
G_message(_("The minimum value for the test (rms=%lf) was "
321
"obtained with: lambda_i = %.3f"),
325
*lambda_min = lambda[lbd_min];
328
G_message(_("Table of results:"));
329
fprintf(stdout, _(" lambda | mean | rms |\n"));
330
for (lbd = 0; lbd < PARAM_LAMBDA; lbd++) {
331
fprintf(stdout, " %9.5f | %10.4f | %10.4f |\n", lambda[lbd],
332
mean[lbd], rms[lbd]);
337
} /* ENDIF (ndata > 0) */
339
G_warning(_("No point lies into the current region"));
346
void interpolation(struct ParamInterp *interp, boolean bilin)
348
if (bilin == P_BILINEAR) { /* Bilinear interpolation */
349
normalDefBilin(interp->N, interp->TN, interp->Q, interp->obsVect,
350
interp->passoE, interp->passoN, interp->nsplx,
351
interp->nsply, interp->region.west,
352
interp->region.south, interp->ndata,
353
interp->nparam_spl, interp->BW);
355
nCorrectGrad(interp->N, interp->lambda[lbd], interp->nsplx,
356
interp->nsply, interp->passoE, interp->passoN);
358
else { /* Bicubic interpolation */
359
normalDefBicubic(interp->N, interp->TN, interp->Q, interp->obsVect,
360
interp->passoE, interp->passoN, interp->nsplx,
361
interp->nsply, interp->region.west,
362
interp->region.south, interp->ndata,
363
interp->nparam_spl, interp->BW);
365
nCorrectGrad(interp->N, interp->lambda[lbd], interp->nsplx,
366
interp->nsply, interp->passoE, interp->passoN);
372
double calc_mean(double *values, int nvalues)
379
for (i = 0; i < nvalues; i++)
381
return sum / nvalues;
385
double calc_root_mean_square(double *values, int nvalues)
388
double rms, sum = .0;
393
for (i = 0; i < nvalues; i++)
394
sum += pow(values[i], 2) / nvalues;
401
double calc_standard_deviation(double *values, int nvalues)
403
double mean, rms, stdev;
408
rms = calc_root_mean_square(values, nvalues);
409
mean = calc_mean(values, nvalues);
411
stdev = sqrt(pow(rms, 2) - pow(mean, 2));
415
struct Stats alloc_Stats(int n)
421
err = (double *)G_calloc(n, sizeof(double));
422
stm = (double *)G_calloc(n, sizeof(double));
430
double find_minimum(double *values, int *l_min)
437
for (l = 0; l < PARAM_LAMBDA; l++) {
438
if (min > values[l]) {
446
struct Point *swap(struct Point *point, int a, int b)
448
/* Once the last value is left out, it is swaped with j-value */
449
SWAP(point[a].coordX, point[b].coordX);
450
SWAP(point[a].coordY, point[b].coordY);
451
SWAP(point[a].coordZ, point[b].coordZ);
452
SWAP(point[a].cat, point[b].cat);