JDFTx  1.2.0
Spline.h
Go to the documentation of this file.
1 /*-------------------------------------------------------------------
2 Copyright 2011 Ravishankar Sundararaman
3 
4 This file is part of JDFTx.
5 
6 JDFTx is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10 
11 JDFTx is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with JDFTx. If not, see <http://www.gnu.org/licenses/>.
18 -------------------------------------------------------------------*/
19 
20 #ifndef JDFTX_CORE_SPLINE_H
21 #define JDFTX_CORE_SPLINE_H
22 
25 
26 #include <cstdio>
27 #include <vector>
28 #include <core/scalar.h>
29 
31 namespace QuinticSpline
32 {
37  std::vector<double> getCoeff(const std::vector<double>& samples, bool oddExtension=false);
38 
43  __hostanddev__ double value(const double* coeff, double x);
44 
49  __hostanddev__ double deriv(const double* coeff, double x);
50 
54  __hostanddev__ void valueGrad(double E_value, double* E_coeff, double x);
55 }
56 
57 
58 //###################################################################################################
59 //#### Implementation ####
60 //##########################
62 
63 #include <cmath>
64 
65 namespace QuinticSpline
66 {
67  __hostanddev__ void getBernsteinCoeffs(const double* coeff, double x, double& tR, double& tL, double (&b)[6])
68  { int j = (int)x;
69  tR = x - j; //right weight for interval
70  tL = 1.-tR; //left weight for interval
71  //Load blip coefficients:
72  double c[6];
73  for(int i=0; i<6; i++) c[i] = coeff[j+i];
74  //Convert to Bernstein polynomial coefficients:
75  b[0] = (1./66) * (c[0] + 26*c[1] + 66*c[2] + 26*c[3] + c[4]);
76  b[1] = (1./33) * (8*c[1] + 33*c[2] + 18*c[3] + c[4]);
77  b[2] = (2./33) * (2*c[1] + 15*c[2] + 12*c[3] + c[4]);
78  b[3] = (2./33) * (c[1] + 12*c[2] + 15*c[3] + 2*c[4]);
79  b[4] = (1./33) * (c[1] + 18*c[2] + 33*c[3] + 8*c[4]);
80  b[5] = (1./66) * (c[1] + 26*c[2] + 66*c[3] + 26*c[4] + c[5]);
81  }
82 
83  //Compute value of quintic spline
84  __hostanddev__ double value(const double* coeff, double x)
85  { double tR, tL, b[6]; getBernsteinCoeffs(coeff, x, tR, tL, b);
86  //Evaluate Bernstein polynomial by de Casteljau's reduction
87  double c[5], d[4];
88  for(int i=0; i<5; i++) c[i] = tL*b[i] + tR*b[i+1]; //5->4
89  for(int i=0; i<4; i++) d[i] = tL*c[i] + tR*c[i+1]; //4->3
90  for(int i=0; i<3; i++) c[i] = tL*d[i] + tR*d[i+1]; //3->2
91  for(int i=0; i<2; i++) d[i] = tL*c[i] + tR*c[i+1]; //2->1
92  return tL*d[0] + tR*d[1]; //1->0
93  }
94 
95  //Compute derivative of quintic spline
96  __hostanddev__ double deriv(const double* coeff, double x)
97  { double tR, tL, b[6]; getBernsteinCoeffs(coeff, x, tR, tL, b);
98  //Derivative by by de Casteljau's reduction
99  double c[5], d[4];
100  for(int i=0; i<5; i++) c[i] = b[i+1] - b[i]; //5->4
101  for(int i=0; i<4; i++) d[i] = tL*c[i] + tR*c[i+1]; //4->3
102  for(int i=0; i<3; i++) c[i] = tL*d[i] + tR*d[i+1]; //3->2
103  for(int i=0; i<2; i++) d[i] = tL*c[i] + tR*c[i+1]; //2->1
104  return 5.*(tL*d[0] + tR*d[1]); //1->0
105  }
106 
107  //Gradient propagation corresponding to value
108  //On the GPU, final results are accumulated using shared memory. (Uses 6 doubles per thread of the thread-block)
109  #ifdef __CUDA_ARCH__
110  extern __shared__ double shared_E_coeff[];
111  #endif
112  __hostanddev__ void valueGrad(double E_value, double* E_coeff, double x)
113  { int j = (int)x;
114  double tR = x - j; //right weight for interval
115  double tL = 1.-tR; //left weight for interval
116  double b[6], c[6];
117  //Backtrace de Casteljau's reduction:
118  b[0]=tL; b[1]=tR; //0->1
119  c[0]=0.; for(int i=0; i<2; i++) { c[i] += tL*b[i]; c[i+1] = tR*b[i]; } //1->2
120  b[0]=0.; for(int i=0; i<3; i++) { b[i] += tL*c[i]; b[i+1] = tR*c[i]; } //2->3
121  c[0]=0.; for(int i=0; i<4; i++) { c[i] += tL*b[i]; c[i+1] = tR*b[i]; } //3->4
122  b[0]=0.; for(int i=0; i<5; i++) { b[i] += tL*c[i]; b[i+1] = tR*c[i]; } //4->5
123  //Propagate from Bernstein coefficients 'b' to blip coefficients 'c':
124  c[0] = (1./66) * (b[0]);
125  c[1] = (1./66) * (26*b[0] + 16*b[1] + 8*b[2] + 4*b[3] + 2*b[4] + b[5]);
126  c[2] = (1./33) * (33*b[0] + 33*b[1] + 30*b[2] + 24*b[3] + 18*b[4] + 13*b[5]);
127  c[3] = (1./33) * (13*b[0] + 18*b[1] + 24*b[2] + 30*b[3] + 33*b[4] + 33*b[5]);
128  c[4] = (1./66) * (b[0] + 2*b[1] + 4*b[2] + 8*b[3] + 16*b[4] + 26*b[5]);
129  c[5] = (1./66) * (b[5]);
130  //Accumulate E_coeff:
131  #ifndef __CUDA_ARCH__
132  for(int i=0; i<6; i++) E_coeff[j+i] += E_value * c[i];
133  #else
134  int iThread = threadIdx.x;
135  for(int i=0; i<6; i++) shared_E_coeff[iThread*6+i] = E_value * c[i];
136  //Accumulate results to first thread:
137  int extent = blockDim.x/2;
138  int stride = (blockDim.x+1)/2;
139  while(extent)
140  { __syncthreads();
141  if(iThread<extent)
142  for(int i=0; i<6; i++) shared_E_coeff[iThread*6+i] += shared_E_coeff[(stride+iThread)*6+i];
143  extent = stride/2;
144  stride = (stride+1)/2;
145  }
146  __syncthreads();
147  //Save to the global memory:
148  if(iThread==0)
149  for(int i=0; i<6; i++) E_coeff[j+i] += shared_E_coeff[i];
150  #endif
151  }
152 }
154 
155 #endif // JDFTX_CORE_SPLINE_H
__hostanddev__ double value(const double *coeff, double x)
Compute value of quintic spline. Warning: x is not range-checked.
std::vector< double > getCoeff(const std::vector< double > &samples, bool oddExtension=false)
Generate quintic spline coefficients for a set of uniformly-spaced samples.
C4-continuous interpolation using quintic splines.
Definition: Spline.h:31
__hostanddev__ void valueGrad(double E_value, double *E_coeff, double x)
Gradient propagation corresponding to value()
__hostanddev__ double deriv(const double *coeff, double x)
Compute derivative (w.r.t x) of quintic spline. Warning: x is not range-checked.