Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
SplineInterp.cc
Go to the documentation of this file.
1 // -*- mode:c++;tab-width:2;indent-tabs-mode:t;show-trailing-whitespace:t;rm-trailing-spaces:t -*-
2 // vi: set ts=2 noet:
3 //
4 // (c) Copyright Rosetta Commons Member Institutions.
5 // (c) This file is part of the Rosetta software suite and is made available under license.
6 // (c) The Rosetta software is developed by the contributing members of the Rosetta Commons.
7 // (c) For more information, see http://www.rosettacommons.org. Questions about this can be
8 // (c) addressed to University of Washington UW TechTransfer, email: license@u.washington.edu.
9 
10 /// @file core/scoring/methods/electron_density/SplineInterp.cc
11 /// @brief 3D spline interpolation methods. Based on implementation by Philippe Thevenaz, see comments below.
12 
13 
14 // Fast 3d spline interpolation routines
15 // --> pretty specific to density map interpolation (3d only, periodic boundaries)
16 // so it lives in core/scoring/methods/electron_density
17 //
18 // Based on implementation by Philippe Thevenaz.
19 // See http://bigwww.epfl.ch/thevenaz/interpolation/ for details.
20 
22 
23 #include <cmath>
24 #include <float.h> // for DBL_EPSILON
25 #include <vector>
26 #include <iostream>
27 
28 
29 namespace core {
30 namespace scoring {
31 namespace electron_density {
32 namespace SplineInterp {
33 
34 void put_line(double* data, int dim, int x1, int x2, double line[], int dims[]) {
35  int i, inc;
36  double* ptr;
37 
38  if (dim == 0) { // x1 == y, x2 == z
39  ptr = &data[x1*dims[2] + x2];
40  inc = dims[1]*dims[2];
41  } else if (dim == 1) { // x1 == x, x2 == z
42  ptr = &data[x1*dims[1]*dims[2] + x2];
43  inc = dims[2];
44  } else { // x1 == x, x2 == y
45  ptr = &data[x1*dims[1]*dims[2] + x2*dims[2]];
46  inc = 1;
47  }
48 
49  for (i=0; i<dims[dim]; i++) {
50  *ptr = line[i] ;
51  ptr = &ptr[inc];
52  }
53 }
54 
55 
56 void get_line(double* data, int dim, int x1, int x2, double line[], int dims[]) {
57  int i, inc;
58  double* ptr;
59 
60  if (dim == 0) { // x1 == y, x2 == z
61  ptr = &data[x1*dims[2] + x2];
62  inc = dims[1]*dims[2];
63  } else if (dim == 1) { // x1 == x, x2 == z
64  ptr = &data[x1*dims[1]*dims[2] + x2];
65  inc = dims[2];
66  } else { // x1 == x, x2 == y
67  ptr = &data[x1*dims[1]*dims[2] + x2*dims[2]];
68  inc = 1;
69  }
70 
71  for (i=0; i<dims[dim]; i++) {
72  line[i] = *ptr;
73  ptr = &ptr[inc];
74  }
75 }
76 
77 static double InitialCausalCoefficient
78  (
79  double c[], // coefficients
80  long DataLength, // number of coefficients
81  double z, // actual pole
82  double Tolerance // admissible relative error
83  )
84 {
85 
86  double Sum, zn;
87  long n, Horizon;
88 
89  // this initialization corresponds to mirror boundaries
90  // modified FPD -- periodic boundaries
91  Horizon = DataLength;
92  if (Tolerance > 0.0) {
93  Horizon = (long)ceil(log(Tolerance) / log(fabs(z)));
94  }
95  if (Horizon < DataLength) {
96  // accelerated loop
97  zn = z;
98  Sum = c[0];
99  for (n = 1L; n < Horizon; n++) {
100  Sum += zn * c[DataLength - n];
101  zn *= z;
102  }
103  return(Sum);
104  }
105  else {
106  // full loop
107  zn = z;
108  Sum = c[0];
109  for (n = 1L; n < DataLength; n++) {
110  Sum += zn * c[DataLength - n];
111  zn *= z;
112  }
113  return(Sum / (1.0 - zn));
114  }
115 }
116 
117 
118 static double InitialAntiCausalCoefficient
119  (
120  double c[], // coefficients
121  long DataLength, // number of samples or coefficients
122  double z, // actual pole
123  double Tolerance // admissible relative error
124  )
125 {
126  // this initialization corresponds to mirror boundaries
127  // return((z / (z * z - 1.0)) * (z * c[DataLength - 2L] + c[DataLength - 1L]));
128  // modified FPD -- periodic boundaries
129  double Sum, zn;
130  int n, Horizon;
131 
132  Horizon = DataLength;
133  if (Tolerance > 0.0) {
134  Horizon = (long)ceil(log(Tolerance) / log(fabs(z)));
135  }
136  if (Horizon < DataLength) {
137  // accelerated loop
138  zn = z;
139  Sum = c[DataLength-1];
140  for (n = 0L; n < Horizon; n++) {
141  Sum += zn * c[n];
142  zn *= z;
143  }
144  return(-z*Sum);
145  }
146  else {
147  // full loop
148  zn = z;
149  Sum = c[DataLength-1];
150  for (n = 0L; n < DataLength-1; n++) {
151  Sum += zn * c[n];
152  zn *= z;
153  }
154  return(-z*Sum / (1.0 - zn));
155  }
156 }
157 
158 
159 
161  (
162  double c[], // input samples --> output coefficients
163  long DataLength, // number of samples or coefficients
164  double z[], // poles
165  long NbPoles, // number of poles
166  double Tolerance // admissible relative error
167  )
168 {
169 
170  double Lambda = 1.0;
171  long n, k;
172 
173  // special case required by mirror boundaries
174  if (DataLength == 1L) {
175  return;
176  }
177  // compute the overall gain
178  for (k = 0L; k < NbPoles; k++) {
179  Lambda = Lambda * (1.0 - z[k]) * (1.0 - 1.0 / z[k]);
180  }
181  // apply the gain
182  for (n = 0L; n < DataLength; n++) {
183  c[n] *= Lambda;
184  }
185  // loop over all poles
186  for (k = 0L; k < NbPoles; k++) {
187  // causal initialization
188  c[0] = InitialCausalCoefficient(c, DataLength, z[k], Tolerance);
189  // causal recursion
190  for (n = 1L; n < DataLength; n++) {
191  c[n] += z[k] * c[n - 1L];
192  }
193  // anticausal initialization
194  c[DataLength - 1L] = InitialAntiCausalCoefficient(c, DataLength, z[k], Tolerance);
195  // anticausal recursion
196  for (n = DataLength - 2L; 0 <= n; n--) {
197  c[n] = z[k] * (c[n + 1L] - c[n]);
198  }
199  }
200 }
201 
202 //////////////////////////////////
203 
204 int compute_coefficients(double *data, int dims[3], int degree) {
205  //double *line;
206  std::vector< double > line;
207  double Pole[2];
208  int NbPoles;
209  int x,y,z;
210 
211  // recover the poles from a lookup table
212  switch (degree) {
213  case 2L:
214  NbPoles = 1;
215  Pole[0] = sqrt(8.0) - 3.0;
216  break;
217  case 3L:
218  NbPoles = 1;
219  Pole[0] = sqrt(3.0) - 2.0;
220  break;
221  case 4L:
222  NbPoles = 2;
223  Pole[0] = sqrt(664.0 - sqrt(438976.0)) + sqrt(304.0) - 19.0;
224  Pole[1] = sqrt(664.0 + sqrt(438976.0)) - sqrt(304.0) - 19.0;
225  break;
226  case 5L:
227  NbPoles = 2;
228  Pole[0] = sqrt(135.0 / 2.0 - sqrt(17745.0 / 4.0)) + sqrt(105.0 / 4.0)
229  - 13.0 / 2.0;
230  Pole[1] = sqrt(135.0 / 2.0 + sqrt(17745.0 / 4.0)) - sqrt(105.0 / 4.0)
231  - 13.0 / 2.0;
232  break;
233  default:
234  std::cerr << "Invalid spline degree\n";
235  return(1);
236  }
237 
238 
239  // convert the image samples into interpolation coefficients
240  // in-place separable process, along x
241  //line = (double *)malloc((size_t)(dims[0] * sizeof(double)));
242  line.resize( dims[0] );
243  if ((int)line.size() != dims[0]) { std::cerr << "Row allocation failed\n"; return(1); }
244  for (y = 0L; y < dims[1]; y++) {
245  for (z = 0L; z < dims[2]; z++) {
246  get_line(data, 0, y, z, &line[0], dims);
247  ConvertToInterpolationCoefficients(&line[0], dims[0], Pole, NbPoles, DBL_EPSILON);
248  put_line(data, 0, y, z, &line[0], dims);
249  }
250  }
251  //free(line);
252 
253  // in-place separable process, along y
254  //line = (double *)malloc((size_t)(dims[1] * sizeof(double)));
255  line.resize( dims[1] );
256  if ((int)line.size() != dims[1]) { std::cerr << "Row allocation failed\n"; return(1); }
257  for (x = 0L; x < dims[0]; x++) {
258  for (z = 0L; z < dims[2]; z++) {
259  get_line(data, 1, x, z, &line[0], dims);
260  ConvertToInterpolationCoefficients(&line[0], dims[1], Pole, NbPoles, DBL_EPSILON);
261  put_line(data, 1, x, z, &line[0], dims);
262  }
263  }
264  //free(line);
265 
266  // in-place separable process, along z
267  //line = (double *)malloc((size_t)(dims[2] * sizeof(double)));
268  line.resize( dims[2] );
269  if ((int)line.size() != dims[2]) { std::cerr << "Row allocation failed\n"; return(1); }
270  for (x = 0L; x < dims[0]; x++) {
271  for (y = 0L; y < dims[1]; y++) {
272  get_line(data, 2, x, y, &line[0], dims);
273  ConvertToInterpolationCoefficients(&line[0], dims[2], Pole, NbPoles, DBL_EPSILON);
274  put_line(data, 2, x, y, &line[0], dims);
275  }
276  }
277  //free(line);
278 
279  return(0);
280 }
281 
282 
283 int grad3(double grad[3], double *Bcoeff, int dims[3], double X[3], int degree) {
284  double wt[3][6];
285  double w, w2, w4, t, t0, t1;
286  double sum_k, sum_jk;
287  int idx[3][6];
288  int i,j,k, pt, dim, gradDim;
289 
290 
291  // compute interpolation indexes
292  for (gradDim=0; gradDim<3; gradDim++) {
293  for (dim=0; dim<3; dim++) {
294  pt = (int)floor(X[dim] - (degree-1) / 2.0);
295  for (i = 0L; i <= degree; i++)
296  idx[dim][i] = pt++;
297 
298  // compute the interpolation weights
299  if (dim == gradDim) {
300  switch (degree) {
301  case 3L:
302  w = X[dim] - (double)idx[dim][1];
303  wt[dim][2] = 3.0 / 4.0 - w * w;
304  wt[dim][3] = (1.0 / 2.0) * (w - wt[dim][2] + 1.0);
305  wt[dim][1] = 1.0 - wt[dim][2] - wt[dim][3];
306 
307  // fprintf(stderr, "*** % 10.4f ::: %10.4f %10.4f %10.4f\n", w, wt[dim][1], wt[dim][2], wt[dim][3]);
308  wt[dim][0] = - wt[dim][1];
309  wt[dim][1] = wt[dim][1] - wt[dim][2];
310  wt[dim][2] = wt[dim][2] - wt[dim][3];
311  break;
312  default:
313  std::cerr << "Invalid spline degree\n";
314  return(1);
315  }
316  } else {
317  switch (degree) {
318  case 2L:
319  w = X[dim] - (double)idx[dim][1];
320  wt[dim][1] = 3.0 / 4.0 - w * w;
321  wt[dim][2] = (1.0 / 2.0) * (w - wt[dim][1] + 1.0);
322  wt[dim][0] = 1.0 - wt[dim][1] - wt[dim][2];
323  break;
324  case 3L:
325  w = X[dim] - (double)idx[dim][1];
326  wt[dim][3] = (1.0 / 6.0) * w * w * w;
327  wt[dim][0] = (1.0 / 6.0) + (1.0 / 2.0) * w * (w - 1.0) - wt[dim][3];
328  wt[dim][2] = w + wt[dim][0] - 2.0 * wt[dim][3];
329  wt[dim][1] = 1.0 - wt[dim][0] - wt[dim][2] - wt[dim][3];
330  break;
331  case 4L:
332  w = X[dim] - (double)idx[dim][2];
333  w2 = w * w;
334  t = (1.0 / 6.0) * w2;
335  wt[dim][0] = 1.0 / 2.0 - w;
336  wt[dim][0] *= wt[dim][0];
337  wt[dim][0] *= (1.0 / 24.0) * wt[dim][0];
338  t0 = w * (t - 11.0 / 24.0);
339  t1 = 19.0 / 96.0 + w2 * (1.0 / 4.0 - t);
340  wt[dim][1] = t1 + t0;
341  wt[dim][3] = t1 - t0;
342  wt[dim][4] = wt[dim][0] + t0 + (1.0 / 2.0) * w;
343  wt[dim][2] = 1.0 - wt[dim][0] - wt[dim][1] - wt[dim][3] - wt[dim][4];
344  break;
345  case 5L:
346  w = X[dim] - (double)idx[dim][2];
347  w2 = w * w;
348  wt[dim][5] = (1.0 / 120.0) * w * w2 * w2;
349  w2 -= w;
350  w4 = w2 * w2;
351  w -= 1.0 / 2.0;
352  t = w2 * (w2 - 3.0);
353  wt[dim][0] = (1.0 / 24.0) * (1.0 / 5.0 + w2 + w4) - wt[dim][5];
354  t0 = (1.0 / 24.0) * (w2 * (w2 - 5.0) + 46.0 / 5.0);
355  t1 = (-1.0 / 12.0) * w * (t + 4.0);
356  wt[dim][2] = t0 + t1;
357  wt[dim][3] = t0 - t1;
358  t0 = (1.0 / 16.0) * (9.0 / 5.0 - t);
359  t1 = (1.0 / 24.0) * w * (w4 - w2 - 5.0);
360  wt[dim][1] = t0 + t1;
361  wt[dim][4] = t0 - t1;
362  break;
363  default:
364  std::cerr << "Invalid spline degree\n";
365  return(1);
366  }
367  }
368 
369  // _periodic_ boundary conditions
370  for (i = 0L; i <= degree; i++) {
371  if (dims[dim] == 1)
372  idx[dim][i] = 0;
373  else
374  idx[dim][i] = idx[dim][i] % dims[dim];
375  if (idx[dim][i] < 0)
376  idx[dim][i] += dims[dim];
377  }
378  }
379 
380  grad[gradDim] = 0.0;
381  for (i = 0; i <= degree; i++) { // x
382  // fprintf(stderr, "%10.4f %10.4f %10.4f\n", wt[0][i], wt[1][i], wt[2][i]);
383 
384  sum_jk = 0.0;
385  for (j = 0; j <= degree; j++) { // y
386  sum_k = 0.0;
387  for (k = 0; k <= degree; k++) { // z
388  sum_k += wt[2][k] * Bcoeff[idx[0][i]*dims[1]*dims[2] + idx[1][j]*dims[2] + idx[2][k]];
389  }
390  sum_jk += wt[1][j] * sum_k;
391  }
392  grad[gradDim] += wt[0][i] * sum_jk;
393  }
394  // fprintf(stderr, "---------------------------\n");
395  }
396 
397  return(0);
398 }
399 
400 
401 double interp3(double *Bcoeff, int dims[3], double X[3], int degree) {
402  double wt[3][6];
403  double value;
404  double w, w2, w4, t, t0, t1;
405  double sum_k, sum_jk;
406  int idx[3][6];
407  int i,j,k, pt, dim;
408 
409  // interpolation indexes
410  for (dim=0; dim<3; dim++) {
411  pt = (int)floor(X[dim] - (degree-1) / 2.0);
412  for (i = 0L; i <= degree; i++)
413  idx[dim][i] = pt++;
414 
415  // interpolation weights
416  switch (degree) {
417  case 2L:
418  w = X[dim] - (double)idx[dim][1];
419  wt[dim][1] = 3.0 / 4.0 - w * w;
420  wt[dim][2] = (1.0 / 2.0) * (w - wt[dim][1] + 1.0);
421  wt[dim][0] = 1.0 - wt[dim][1] - wt[dim][2];
422  break;
423  case 3L:
424  w = X[dim] - (double)idx[dim][1];
425  wt[dim][3] = (1.0 / 6.0) * w * w * w;
426  wt[dim][0] = (1.0 / 6.0) + (1.0 / 2.0) * w * (w - 1.0) - wt[dim][3];
427  wt[dim][2] = w + wt[dim][0] - 2.0 * wt[dim][3];
428  wt[dim][1] = 1.0 - wt[dim][0] - wt[dim][2] - wt[dim][3];
429  break;
430  case 4L:
431  w = X[dim] - (double)idx[dim][2];
432  w2 = w * w;
433  t = (1.0 / 6.0) * w2;
434  wt[dim][0] = 1.0 / 2.0 - w;
435  wt[dim][0] *= wt[dim][0];
436  wt[dim][0] *= (1.0 / 24.0) * wt[dim][0];
437  t0 = w * (t - 11.0 / 24.0);
438  t1 = 19.0 / 96.0 + w2 * (1.0 / 4.0 - t);
439  wt[dim][1] = t1 + t0;
440  wt[dim][3] = t1 - t0;
441  wt[dim][4] = wt[dim][0] + t0 + (1.0 / 2.0) * w;
442  wt[dim][2] = 1.0 - wt[dim][0] - wt[dim][1] - wt[dim][3] - wt[dim][4];
443  break;
444  case 5L:
445  w = X[dim] - (double)idx[dim][2];
446  w2 = w * w;
447  wt[dim][5] = (1.0 / 120.0) * w * w2 * w2;
448  w2 -= w;
449  w4 = w2 * w2;
450  w -= 1.0 / 2.0;
451  t = w2 * (w2 - 3.0);
452  wt[dim][0] = (1.0 / 24.0) * (1.0 / 5.0 + w2 + w4) - wt[dim][5];
453  t0 = (1.0 / 24.0) * (w2 * (w2 - 5.0) + 46.0 / 5.0);
454  t1 = (-1.0 / 12.0) * w * (t + 4.0);
455  wt[dim][2] = t0 + t1;
456  wt[dim][3] = t0 - t1;
457  t0 = (1.0 / 16.0) * (9.0 / 5.0 - t);
458  t1 = (1.0 / 24.0) * w * (w4 - w2 - 5.0);
459  wt[dim][1] = t0 + t1;
460  wt[dim][4] = t0 - t1;
461  break;
462  default:
463  std::cerr << "Invalid spline degree\n";
464  return(0.0);
465  }
466 
467  // _periodic_ boundary conditions
468  for (i = 0L; i <= degree; i++) {
469  if (dims[dim] == 1)
470  idx[dim][i] = 0;
471  else
472  idx[dim][i] = idx[dim][i] % dims[dim];
473  if (idx[dim][i] < 0)
474  idx[dim][i] += dims[dim];
475  }
476  // mirror boundary conditions
477  // dims2[dim] = 2*dims[dim]-2;
478  // for (k = 0L; k <= degree; k++) {
479  // idx[dim][k] = (dims[dim] == 1L) ? (0L) : ((idx[dim][k] < 0L) ?
480  // (-idx[dim][k] - dims2[dim] * ((-idx[dim][k]) / dims2[dim]))
481  // : (idx[dim][k] - dims2[dim] * (idx[dim][k] / dims2[dim])));
482  // if (dims[dim] <= idx[dim][k]) {
483  // idx[dim][k] = dims2[dim] - idx[dim][k];
484  // }
485  // }
486  }
487 
488  value = 0.0;
489  for (i = 0; i <= degree; i++) { // x
490  sum_jk = 0.0;
491  for (j = 0; j <= degree; j++) { // y
492  sum_k = 0.0;
493  for (k = 0; k <= degree; k++) { // z
494  sum_k += wt[2][k] * Bcoeff[idx[0][i]*dims[1]*dims[2] + idx[1][j]*dims[2] + idx[2][k]];
495  }
496  sum_jk += wt[1][j] * sum_k;
497  }
498  value += wt[0][i] * sum_jk;
499  }
500 
501  return(value);
502 }
503 
504 }
505 }
506 }
507 }
508