Nek5000
SEM for Incompressible NS
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
poly.c
Go to the documentation of this file.
1 #include <stddef.h>
2 #include <stdlib.h>
3 #include <math.h> /* for cos, fabs */
4 #include <float.h>
5 #include <string.h>
6 #include "c99.h"
7 #include "name.h"
8 #include "fail.h"
9 #include "mem.h"
10 
11 #define lagrange_size PREFIXED_NAME(lagrange_size )
12 #define lagrange_setup PREFIXED_NAME(lagrange_setup)
13 #define gauss_nodes PREFIXED_NAME(gauss_nodes )
14 #define gauss_quad PREFIXED_NAME(gauss_quad )
15 #define lobatto_nodes PREFIXED_NAME(lobatto_nodes )
16 #define lobatto_quad PREFIXED_NAME(lobatto_quad )
17 #define gll_lag_size PREFIXED_NAME(gll_lag_size )
18 #define gll_lag_setup PREFIXED_NAME(gll_lag_setup )
19 
20 typedef void lagrange_fun(double *restrict p,
21  double *restrict data, unsigned n, int d, double x);
22 
23 #include "poly_imp.h"
24 
25 static void lagrange_eval(double *restrict p,
26  double *restrict data, unsigned n, int der, double x)
27 {{
28  unsigned i;
29  const double *restrict z=data, *restrict w=z+n;
30  double *restrict d=data+2*n, *restrict u0=d+n, *restrict v0=u0+n;
31  for(i=0;i<n;++i) d[i]=2*(x-z[i]);
32  u0[0 ]=1; for(i=0 ;i<n-1;++i) u0[i+1]=u0[i]*d[i];
33  v0[n-1]=1; for(i=n-1;i ;--i) v0[i-1]=d[i]*v0[i];
34  for(i=0;i<n;++i) p[i]=w[i]*u0[i]*v0[i];
35  if(der>0) {
36  double *restrict p1 = p+n, *restrict u1=v0+n, *restrict v1=u1+n;
37  u1[0 ]=0; for(i=0 ;i<n-1;++i) u1[i+1]=u1[i]*d[i]+u0[i];
38  v1[n-1]=0; for(i=n-1;i ;--i) v1[i-1]=d[i]*v1[i]+v0[i];
39  for(i=0;i<n;++i) p1[i]=2*w[i]*(u1[i]*v0[i]+u0[i]*v1[i]);
40  if(der>1) {
41  double *restrict p2 = p1+n, *restrict u2=v1+n, *restrict v2=u2+n;
42  u2[0 ]=0; for(i=0 ;i<n-1;++i) u2[i+1]=u2[i]*d[i]+2*u1[i];
43  v2[n-1]=0; for(i=n-1;i ;--i) v2[i-1]=d[i]*v2[i]+2*v1[i];
44  for(i=0;i<n;++i)
45  p2[i]=4*w[i]*(u2[i]*v0[i]+2*u1[i]*v1[i]+u0[i]*v2[i]);
46  }
47  }
48 }}
49 
50 static void lagrange_coef(
51  double *restrict p, double *data, double *w, const double *z,
52  unsigned n, lagrange_fun *lag_eval)
53 {
54  unsigned i;
55  for(i=0;i<n;++i) w[i]=1;
56  for(i=0;i<n;++i) lag_eval(p,data,n,0,z[i]), w[i]=1/p[i];
57 }
58 
59 unsigned lagrange_size(unsigned n)
60 {
61  return 9*n;
62 }
63 
65  double *restrict data, const double *restrict z, unsigned n)
66 {
67  double *restrict p = tmalloc(double,n);
68  memcpy(data,z,n*sizeof(double));
69  lagrange_coef(p,data,data+n,z,n,&lagrange_eval);
70  free(p);
71  return &lagrange_eval;
72 }
73 
74 #define EPS (128*DBL_EPSILON)
75 #define PI 3.1415926535897932384626433832795028841971693993751058209749445923
76 
77 /*
78  For brevity's sake, some names have been shortened
79  Quadrature rules
80  Gauss -> Gauss-Legendre quadrature (open)
81  Lobatto -> Gauss-Lobatto-Legendre quadrature (closed at both ends)
82  Polynomial bases
83  Legendre -> Legendre basis
84  Gauss -> Lagrangian basis using Gauss quadrature nodes
85  Lobatto -> Lagrangian basis using Lobatto quadrature nodes
86 */
87 
88 /*--------------------------------------------------------------------------
89  Legendre Polynomial Computation
90  compute P_n(x) or P_n'(x) or P_n''(x)
91  --------------------------------------------------------------------------*/
92 
93 /* precondition: n >= 0 */
94 static double legendre(int n, double x)
95 {
96  double p[2];
97  double i, nn=n-0.5; /* avoid int -> double conversions */
98  p[0]=1.,p[1]=x;
99  for(i=1; i<nn; i+=2) {
100  p[0] = ((2*i+1)*x*p[1]- i *p[0])/(i+1);
101  p[1] = ((2*i+3)*x*p[0]-(i+1)*p[1])/(i+2);
102  }
103  return p[n&1];
104 }
105 
106 /* precondition: n > 0 */
107 static double legendre_d1(int n, double x)
108 {
109  double p[2];
110  double i, nn=n-0.5; /* avoid int -> double conversions */
111  p[0]=3*x,p[1]=1;
112  for(i=2; i<nn; i+=2) {
113  p[1] = ((2*i+1)*x*p[0]-(i+1)*p[1])/i;
114  p[0] = ((2*i+3)*x*p[1]-(i+2)*p[0])/(i+1);
115  }
116  return p[n&1];
117 }
118 
119 /* precondition: n > 1 */
120 static double legendre_d2(int n, double x)
121 {
122  double p[2];
123  double i, nn=n-0.5; /* avoid int -> double conversions */
124  p[0]=3,p[1]=15*x;
125  for(i=3; i<nn; i+=2) {
126  p[0] = ((2*i+1)*x*p[1]-(i+2)*p[0])/(i-1);
127  p[1] = ((2*i+3)*x*p[0]-(i+3)*p[1])/i;
128  }
129  return p[n&1];
130 }
131 
132 /*--------------------------------------------------------------------------
133  Quadrature Nodes and Weights Calculation
134  compute the n Gauss-Legendre nodes and weights or
135  the n Gauss-Lobatto-Legendre nodes and weights
136  --------------------------------------------------------------------------*/
137 
138 /* n nodes */
139 void gauss_nodes(double *restrict z, int n)
140 {
141  int i,j;
142  for(i=0; i<=n/2-1; ++i) {
143  double ox, x = cos( (2*n-2*i-1)*(PI/2)/n );
144  do {
145  ox = x;
146  x -= legendre(n,x)/legendre_d1(n,x);
147  } while(fabs(x-ox)>-x*EPS);
148  z[i] = x - legendre(n,x)/legendre_d1(n,x);
149  }
150  if(n&1) z[n/2]=0;
151  for(j=(n+1)/2,i=n/2-1; j<n; ++j,--i) z[j]=-z[i];
152 }
153 
154 /* n inner lobatto nodes (excluding -1,1) */
155 static void lobatto_nodes_aux(double *restrict z, int n)
156 {
157  int i,j,np=n+1;
158  for(i=0; i<=n/2-1; ++i) {
159  double ox, x = cos( (n-i)*PI/np );
160  do {
161  ox = x;
162  x -= legendre_d1(np,x)/legendre_d2(np,x);
163  } while(fabs(x-ox)>-x*EPS);
164  z[i] = x - legendre_d1(np,x)/legendre_d2(np,x);
165  }
166  if(n&1) z[n/2]=0;
167  for(j=(n+1)/2,i=n/2-1; j<n; ++j,--i) z[j]=-z[i];
168 }
169 
170 /* n lobatto nodes */
171 static void lobatto_nodes_n(double *restrict z, int n)
172 {
173  z[0] = -1, z[n-1] = 1;
174  lobatto_nodes_aux(&z[1],n-2);
175 }
176 
177 static void lobatto_nodes_fix(double *restrict z, int n)
178 {
179  z[0] = -1, z[n-1] = 1;
180  if(n&1) z[n/2]=0;
181  if(n>=4) {
182  const double *restrict gllz = gllz_table[n-4];
183  int i,j;
184  for(i=1;i<=n/2-1;++i) z[i] = -gllz[i-1];
185  for(j=(n+1)/2,i=n/2-1; j<n-1; ++j,--i) z[j] = gllz[i-1];
186  }
187 }
188 
189 void lobatto_nodes(double *restrict z, int n)
190 {
191  if(n>GLL_LAG_FIX_MAX) lobatto_nodes_n(z,n);
192  else if(n>=2) lobatto_nodes_fix(z,n);
193 }
194 
195 void gauss_quad(double *restrict z, double *restrict w, int n)
196 {
197  int i,j;
198  gauss_nodes(z,n);
199  for(i=0; i<=(n-1)/2; ++i) {
200  double d = (n+1)*legendre(n+1,z[i]);
201  w[i] = 2*(1-z[i]*z[i])/(d*d);
202  }
203  for(j=(n+1)/2,i=n/2-1; j<n; ++j,--i) w[j]=w[i];
204 }
205 
206 void lobatto_quad(double *restrict z, double *restrict w, int n)
207 {
208  int i,j;
209  lobatto_nodes(z,n);
210  for(i=0; i<=(n-1)/2; ++i) {
211  double d = legendre(n-1,z[i]);
212  w[i] = 2/((n-1)*n*d*d);
213  }
214  for(j=(n+1)/2,i=n/2-1; j<n; ++j,--i) w[j]=w[i];
215 }
216 
217 unsigned gll_lag_size(unsigned n)
218 {
219  return (n<=GLL_LAG_FIX_MAX?1:9)*n;
220 }
221 
223 {
224  double *z, *w, *p;
225  lagrange_fun *f;
226  if(n<2) return 0;
227  p = tmalloc(double,2*n);
228  if(n<=GLL_LAG_FIX_MAX)
229  f=gll_lag_table[n-2], z=p+n, w=data;
230  else
231  f=&lagrange_eval, z=data, w=z+n;
232  lobatto_nodes(z,n);
233  lagrange_coef(p,data,w,z,n,f);
234  free(p);
235  return f;
236 }
#define tmalloc(type, count)
Definition: mem.h:91
void lagrange_fun(double *restrict p, double *restrict data, unsigned n, int d, double x)
Definition: poly.c:20
#define lobatto_quad
Definition: poly.c:16
n
Definition: xxt_test.m:73
static double legendre(int n, double x)
Definition: poly.c:94
#define x
static const double *const gllz_table[21]
Definition: poly_imp.h:1937
static void lobatto_nodes_n(double *restrict z, int n)
Definition: poly.c:171
#define gauss_quad
Definition: poly.c:14
#define lagrange_setup
Definition: poly.c:12
#define gll_lag_setup
Definition: poly.c:18
static void lobatto_nodes_fix(double *restrict z, int n)
Definition: poly.c:177
p
Definition: xxt_test2.m:1
#define gll_lag_size
Definition: poly.c:17
#define lagrange_size
Definition: poly.c:11
#define GLL_LAG_FIX_MAX
Definition: poly_imp.h:3
static lagrange_fun *const gll_lag_table[23]
Definition: poly_imp.h:1943
static double legendre_d2(int n, double x)
Definition: poly.c:120
#define restrict
Definition: c99.h:11
for i
Definition: xxt_test.m:74
static void lagrange_coef(double *restrict p, double *data, double *w, const double *z, unsigned n, lagrange_fun *lag_eval)
Definition: poly.c:50
static void lobatto_nodes_aux(double *restrict z, int n)
Definition: poly.c:155
#define gauss_nodes
Definition: poly.c:13
#define lobatto_nodes
Definition: poly.c:15
#define PI
Definition: poly.c:75
establishes some macros to establish naming conventions
static uint np
Definition: findpts_test.c:63
static double legendre_d1(int n, double x)
Definition: poly.c:107
static void lagrange_eval(double *restrict p, double *restrict data, unsigned n, int der, double x)
Definition: poly.c:25
#define EPS
Definition: poly.c:74
static double z[NR *NS *NT *N]
Definition: obbox_test.c:31