xref: /petsc/src/dm/dt/interface/dt.c (revision 05d1e344d69cb8974fc87df7165aba7c7ae3d14e)
1 /* Discretization tools */
2 
3 #include <petscconf.h>
4 #if defined(PETSC_HAVE_MATHIMF_H)
5 #include <mathimf.h>           /* this needs to be included before math.h */
6 #endif
7 
8 #include <petscdt.h>            /*I "petscdt.h" I*/ /*I "petscfe.h" I*/
9 #include <petscblaslapack.h>
10 #include <petsc-private/petscimpl.h>
11 #include <petscviewer.h>
12 #include <petscdmplex.h>
13 #include <petscdmshell.h>
14 
15 #undef __FUNCT__
16 #define __FUNCT__ "PetscDTLegendreEval"
17 /*@
18    PetscDTLegendreEval - evaluate Legendre polynomial at points
19 
20    Not Collective
21 
22    Input Arguments:
23 +  npoints - number of spatial points to evaluate at
24 .  points - array of locations to evaluate at
25 .  ndegree - number of basis degrees to evaluate
26 -  degrees - sorted array of degrees to evaluate
27 
28    Output Arguments:
29 +  B - row-oriented basis evaluation matrix B[point*ndegree + degree] (dimension npoints*ndegrees, allocated by caller) (or NULL)
30 .  D - row-oriented derivative evaluation matrix (or NULL)
31 -  D2 - row-oriented second derivative evaluation matrix (or NULL)
32 
33    Level: intermediate
34 
35 .seealso: PetscDTGaussQuadrature()
36 @*/
37 PetscErrorCode PetscDTLegendreEval(PetscInt npoints,const PetscReal *points,PetscInt ndegree,const PetscInt *degrees,PetscReal *B,PetscReal *D,PetscReal *D2)
38 {
39   PetscInt i,maxdegree;
40 
41   PetscFunctionBegin;
42   if (!npoints || !ndegree) PetscFunctionReturn(0);
43   maxdegree = degrees[ndegree-1];
44   for (i=0; i<npoints; i++) {
45     PetscReal pm1,pm2,pd1,pd2,pdd1,pdd2,x;
46     PetscInt  j,k;
47     x    = points[i];
48     pm2  = 0;
49     pm1  = 1;
50     pd2  = 0;
51     pd1  = 0;
52     pdd2 = 0;
53     pdd1 = 0;
54     k    = 0;
55     if (degrees[k] == 0) {
56       if (B) B[i*ndegree+k] = pm1;
57       if (D) D[i*ndegree+k] = pd1;
58       if (D2) D2[i*ndegree+k] = pdd1;
59       k++;
60     }
61     for (j=1; j<=maxdegree; j++,k++) {
62       PetscReal p,d,dd;
63       p    = ((2*j-1)*x*pm1 - (j-1)*pm2)/j;
64       d    = pd2 + (2*j-1)*pm1;
65       dd   = pdd2 + (2*j-1)*pd1;
66       pm2  = pm1;
67       pm1  = p;
68       pd2  = pd1;
69       pd1  = d;
70       pdd2 = pdd1;
71       pdd1 = dd;
72       if (degrees[k] == j) {
73         if (B) B[i*ndegree+k] = p;
74         if (D) D[i*ndegree+k] = d;
75         if (D2) D2[i*ndegree+k] = dd;
76       }
77     }
78   }
79   PetscFunctionReturn(0);
80 }
81 
82 #undef __FUNCT__
83 #define __FUNCT__ "PetscDTGaussQuadrature"
84 /*@
85    PetscDTGaussQuadrature - create Gauss quadrature
86 
87    Not Collective
88 
89    Input Arguments:
90 +  npoints - number of points
91 .  a - left end of interval (often-1)
92 -  b - right end of interval (often +1)
93 
94    Output Arguments:
95 +  x - quadrature points
96 -  w - quadrature weights
97 
98    Level: intermediate
99 
100    References:
101    Golub and Welsch, Calculation of Quadrature Rules, Math. Comp. 23(106), 221--230, 1969.
102 
103 .seealso: PetscDTLegendreEval()
104 @*/
105 PetscErrorCode PetscDTGaussQuadrature(PetscInt npoints,PetscReal a,PetscReal b,PetscReal *x,PetscReal *w)
106 {
107   PetscErrorCode ierr;
108   PetscInt       i;
109   PetscReal      *work;
110   PetscScalar    *Z;
111   PetscBLASInt   N,LDZ,info;
112 
113   PetscFunctionBegin;
114   /* Set up the Golub-Welsch system */
115   for (i=0; i<npoints; i++) {
116     x[i] = 0;                   /* diagonal is 0 */
117     if (i) w[i-1] = 0.5 / PetscSqrtReal(1 - 1./PetscSqr(2*i));
118   }
119   ierr = PetscRealView(npoints-1,w,PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
120   ierr = PetscMalloc2(npoints*npoints,PetscScalar,&Z,PetscMax(1,2*npoints-2),PetscReal,&work);CHKERRQ(ierr);
121   ierr = PetscBLASIntCast(npoints,&N);CHKERRQ(ierr);
122   LDZ  = N;
123   ierr = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr);
124   PetscStackCallBLAS("LAPACKsteqr",LAPACKsteqr_("I",&N,x,w,Z,&LDZ,work,&info));
125   ierr = PetscFPTrapPop();CHKERRQ(ierr);
126   if (info) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"xSTEQR error");
127 
128   for (i=0; i<(npoints+1)/2; i++) {
129     PetscReal y = 0.5 * (-x[i] + x[npoints-i-1]); /* enforces symmetry */
130     x[i]           = (a+b)/2 - y*(b-a)/2;
131     x[npoints-i-1] = (a+b)/2 + y*(b-a)/2;
132 
133     w[i] = w[npoints-1-i] = (b-a)*PetscSqr(0.5*PetscAbsScalar(Z[i*npoints] + Z[(npoints-i-1)*npoints]));
134   }
135   ierr = PetscFree2(Z,work);CHKERRQ(ierr);
136   PetscFunctionReturn(0);
137 }
138 
139 #undef __FUNCT__
140 #define __FUNCT__ "PetscDTFactorial_Internal"
141 /* Evaluates the nth jacobi polynomial with weight parameters a,b at a point x.
142    Recurrence relations implemented from the pseudocode given in Karniadakis and Sherwin, Appendix B */
143 PETSC_STATIC_INLINE PetscErrorCode PetscDTFactorial_Internal(PetscInt n, PetscReal *factorial)
144 {
145   PetscReal f = 1.0;
146   PetscInt  i;
147 
148   PetscFunctionBegin;
149   for (i = 1; i < n+1; ++i) f *= i;
150   *factorial = f;
151   PetscFunctionReturn(0);
152 }
153 
154 #undef __FUNCT__
155 #define __FUNCT__ "PetscDTComputeJacobi"
156 /* Evaluates the nth jacobi polynomial with weight parameters a,b at a point x.
157    Recurrence relations implemented from the pseudocode given in Karniadakis and Sherwin, Appendix B */
158 PETSC_STATIC_INLINE PetscErrorCode PetscDTComputeJacobi(PetscReal a, PetscReal b, PetscInt n, PetscReal x, PetscReal *P)
159 {
160   PetscReal apb, pn1, pn2;
161   PetscInt  k;
162 
163   PetscFunctionBegin;
164   if (!n) {*P = 1.0; PetscFunctionReturn(0);}
165   if (n == 1) {*P = 0.5 * (a - b + (a + b + 2.0) * x); PetscFunctionReturn(0);}
166   apb = a + b;
167   pn2 = 1.0;
168   pn1 = 0.5 * (a - b + (apb + 2.0) * x);
169   *P  = 0.0;
170   for (k = 2; k < n+1; ++k) {
171     PetscReal a1 = 2.0 * k * (k + apb) * (2.0*k + apb - 2.0);
172     PetscReal a2 = (2.0 * k + apb - 1.0) * (a*a - b*b);
173     PetscReal a3 = (2.0 * k + apb - 2.0) * (2.0 * k + apb - 1.0) * (2.0 * k + apb);
174     PetscReal a4 = 2.0 * (k + a - 1.0) * (k + b - 1.0) * (2.0 * k + apb);
175 
176     a2  = a2 / a1;
177     a3  = a3 / a1;
178     a4  = a4 / a1;
179     *P  = (a2 + a3 * x) * pn1 - a4 * pn2;
180     pn2 = pn1;
181     pn1 = *P;
182   }
183   PetscFunctionReturn(0);
184 }
185 
186 #undef __FUNCT__
187 #define __FUNCT__ "PetscDTComputeJacobiDerivative"
188 /* Evaluates the first derivative of P_{n}^{a,b} at a point x. */
189 PETSC_STATIC_INLINE PetscErrorCode PetscDTComputeJacobiDerivative(PetscReal a, PetscReal b, PetscInt n, PetscReal x, PetscReal *P)
190 {
191   PetscReal      nP;
192   PetscErrorCode ierr;
193 
194   PetscFunctionBegin;
195   if (!n) {*P = 0.0; PetscFunctionReturn(0);}
196   ierr = PetscDTComputeJacobi(a+1, b+1, n-1, x, &nP);CHKERRQ(ierr);
197   *P   = 0.5 * (a + b + n + 1) * nP;
198   PetscFunctionReturn(0);
199 }
200 
201 #undef __FUNCT__
202 #define __FUNCT__ "PetscDTMapSquareToTriangle_Internal"
203 /* Maps from [-1,1]^2 to the (-1,1) reference triangle */
204 PETSC_STATIC_INLINE PetscErrorCode PetscDTMapSquareToTriangle_Internal(PetscReal x, PetscReal y, PetscReal *xi, PetscReal *eta)
205 {
206   PetscFunctionBegin;
207   *xi  = 0.5 * (1.0 + x) * (1.0 - y) - 1.0;
208   *eta = y;
209   PetscFunctionReturn(0);
210 }
211 
212 #undef __FUNCT__
213 #define __FUNCT__ "PetscDTMapCubeToTetrahedron_Internal"
214 /* Maps from [-1,1]^2 to the (-1,1) reference triangle */
215 PETSC_STATIC_INLINE PetscErrorCode PetscDTMapCubeToTetrahedron_Internal(PetscReal x, PetscReal y, PetscReal z, PetscReal *xi, PetscReal *eta, PetscReal *zeta)
216 {
217   PetscFunctionBegin;
218   *xi   = 0.25 * (1.0 + x) * (1.0 - y) * (1.0 - z) - 1.0;
219   *eta  = 0.5  * (1.0 + y) * (1.0 - z) - 1.0;
220   *zeta = z;
221   PetscFunctionReturn(0);
222 }
223 
224 #undef __FUNCT__
225 #define __FUNCT__ "PetscDTGaussJacobiQuadrature1D_Internal"
226 static PetscErrorCode PetscDTGaussJacobiQuadrature1D_Internal(PetscInt npoints, PetscReal a, PetscReal b, PetscReal *x, PetscReal *w)
227 {
228   PetscInt       maxIter = 100;
229   PetscReal      eps     = 1.0e-8;
230   PetscReal      a1, a2, a3, a4, a5, a6;
231   PetscInt       k;
232   PetscErrorCode ierr;
233 
234   PetscFunctionBegin;
235 
236   a1      = pow(2, a+b+1);
237 #if defined(PETSC_HAVE_TGAMMA)
238   a2      = tgamma(a + npoints + 1);
239   a3      = tgamma(b + npoints + 1);
240   a4      = tgamma(a + b + npoints + 1);
241 #else
242   SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"tgamma() - math routine is unavailable.");
243 #endif
244 
245   ierr = PetscDTFactorial_Internal(npoints, &a5);CHKERRQ(ierr);
246   a6   = a1 * a2 * a3 / a4 / a5;
247   /* Computes the m roots of P_{m}^{a,b} on [-1,1] by Newton's method with Chebyshev points as initial guesses.
248    Algorithm implemented from the pseudocode given by Karniadakis and Sherwin and Python in FIAT */
249   for (k = 0; k < npoints; ++k) {
250     PetscReal r = -cos((2.0*k + 1.0) * PETSC_PI / (2.0 * npoints)), dP;
251     PetscInt  j;
252 
253     if (k > 0) r = 0.5 * (r + x[k-1]);
254     for (j = 0; j < maxIter; ++j) {
255       PetscReal s = 0.0, delta, f, fp;
256       PetscInt  i;
257 
258       for (i = 0; i < k; ++i) s = s + 1.0 / (r - x[i]);
259       ierr = PetscDTComputeJacobi(a, b, npoints, r, &f);CHKERRQ(ierr);
260       ierr = PetscDTComputeJacobiDerivative(a, b, npoints, r, &fp);CHKERRQ(ierr);
261       delta = f / (fp - f * s);
262       r     = r - delta;
263       if (fabs(delta) < eps) break;
264     }
265     x[k] = r;
266     ierr = PetscDTComputeJacobiDerivative(a, b, npoints, x[k], &dP);CHKERRQ(ierr);
267     w[k] = a6 / (1.0 - PetscSqr(x[k])) / PetscSqr(dP);
268   }
269   PetscFunctionReturn(0);
270 }
271 
272 #undef __FUNCT__
273 #define __FUNCT__ "PetscDTGaussJacobiQuadrature"
274 /*@C
275   PetscDTGaussJacobiQuadrature - create Gauss-Jacobi quadrature for a simplex
276 
277   Not Collective
278 
279   Input Arguments:
280 + dim - The simplex dimension
281 . npoints - number of points
282 . a - left end of interval (often-1)
283 - b - right end of interval (often +1)
284 
285   Output Arguments:
286 + points - quadrature points
287 - weights - quadrature weights
288 
289   Level: intermediate
290 
291   References:
292   Karniadakis and Sherwin.
293   FIAT
294 
295 .seealso: PetscDTGaussQuadrature()
296 @*/
297 PetscErrorCode PetscDTGaussJacobiQuadrature(PetscInt dim, PetscInt npoints, PetscReal a, PetscReal b, PetscReal *points[], PetscReal *weights[])
298 {
299   PetscReal     *px, *wx, *py, *wy, *pz, *wz, *x, *w;
300   PetscInt       i, j, k;
301   PetscErrorCode ierr;
302 
303   PetscFunctionBegin;
304   if ((a != -1.0) || (b != 1.0)) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must use default internal right now");
305   switch (dim) {
306   case 1:
307     ierr = PetscMalloc(npoints * sizeof(PetscReal), &x);CHKERRQ(ierr);
308     ierr = PetscMalloc(npoints * sizeof(PetscReal), &w);CHKERRQ(ierr);
309     ierr = PetscDTGaussJacobiQuadrature1D_Internal(npoints, 0.0, 0.0, x, w);CHKERRQ(ierr);
310     break;
311   case 2:
312     ierr = PetscMalloc(npoints*npoints*2 * sizeof(PetscReal), &x);CHKERRQ(ierr);
313     ierr = PetscMalloc(npoints*npoints   * sizeof(PetscReal), &w);CHKERRQ(ierr);
314     ierr = PetscMalloc4(npoints,PetscReal,&px,npoints,PetscReal,&wx,npoints,PetscReal,&py,npoints,PetscReal,&wy);CHKERRQ(ierr);
315     ierr = PetscDTGaussJacobiQuadrature1D_Internal(npoints, 0.0, 0.0, px, wx);CHKERRQ(ierr);
316     ierr = PetscDTGaussJacobiQuadrature1D_Internal(npoints, 1.0, 0.0, py, wy);CHKERRQ(ierr);
317     for (i = 0; i < npoints; ++i) {
318       for (j = 0; j < npoints; ++j) {
319         ierr = PetscDTMapSquareToTriangle_Internal(px[i], py[j], &x[(i*npoints+j)*2+0], &x[(i*npoints+j)*2+1]);CHKERRQ(ierr);
320         w[i*npoints+j] = 0.5 * wx[i] * wy[j];
321       }
322     }
323     ierr = PetscFree4(px,wx,py,wy);CHKERRQ(ierr);
324     break;
325   case 3:
326     ierr = PetscMalloc(npoints*npoints*3 * sizeof(PetscReal), &x);CHKERRQ(ierr);
327     ierr = PetscMalloc(npoints*npoints   * sizeof(PetscReal), &w);CHKERRQ(ierr);
328     ierr = PetscMalloc6(npoints,PetscReal,&px,npoints,PetscReal,&wx,npoints,PetscReal,&py,npoints,PetscReal,&wy,npoints,PetscReal,&pz,npoints,PetscReal,&wz);CHKERRQ(ierr);
329     ierr = PetscDTGaussJacobiQuadrature1D_Internal(npoints, 0.0, 0.0, px, wx);CHKERRQ(ierr);
330     ierr = PetscDTGaussJacobiQuadrature1D_Internal(npoints, 1.0, 0.0, py, wy);CHKERRQ(ierr);
331     ierr = PetscDTGaussJacobiQuadrature1D_Internal(npoints, 2.0, 0.0, pz, wz);CHKERRQ(ierr);
332     for (i = 0; i < npoints; ++i) {
333       for (j = 0; j < npoints; ++j) {
334         for (k = 0; k < npoints; ++k) {
335           ierr = PetscDTMapCubeToTetrahedron_Internal(px[i], py[j], pz[k], &x[((i*npoints+j)*npoints+k)*3+0], &x[((i*npoints+j)*npoints+k)*3+1], &x[((i*npoints+j)*npoints+k)*3+2]);CHKERRQ(ierr);
336           w[(i*npoints+j)*npoints+k] = 0.125 * wx[i] * wy[j] * wz[k];
337         }
338       }
339     }
340     ierr = PetscFree6(px,wx,py,wy,pz,wz);CHKERRQ(ierr);
341     break;
342   default:
343     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct quadrature rule for dimension %d", dim);
344   }
345   if (points)  *points  = x;
346   if (weights) *weights = w;
347   PetscFunctionReturn(0);
348 }
349 
350 #undef __FUNCT__
351 #define __FUNCT__ "PetscDTPseudoInverseQR"
352 /* Overwrites A. Can only handle full-rank problems with m>=n
353  * A in column-major format
354  * Ainv in row-major format
355  * tau has length m
356  * worksize must be >= max(1,n)
357  */
358 static PetscErrorCode PetscDTPseudoInverseQR(PetscInt m,PetscInt mstride,PetscInt n,PetscReal *A_in,PetscReal *Ainv_out,PetscScalar *tau,PetscInt worksize,PetscScalar *work)
359 {
360   PetscErrorCode ierr;
361   PetscBLASInt M,N,K,lda,ldb,ldwork,info;
362   PetscScalar *A,*Ainv,*R,*Q,Alpha;
363 
364   PetscFunctionBegin;
365 #if defined(PETSC_USE_COMPLEX)
366   {
367     PetscInt i,j;
368     ierr = PetscMalloc2(m*n,PetscScalar,&A,m*n,PetscScalar,&Ainv);CHKERRQ(ierr);
369     for (j=0; j<n; j++) {
370       for (i=0; i<m; i++) A[i+m*j] = A_in[i+mstride*j];
371     }
372     mstride = m;
373   }
374 #else
375   A = A_in;
376   Ainv = Ainv_out;
377 #endif
378 
379   ierr = PetscBLASIntCast(m,&M);CHKERRQ(ierr);
380   ierr = PetscBLASIntCast(n,&N);CHKERRQ(ierr);
381   ierr = PetscBLASIntCast(mstride,&lda);CHKERRQ(ierr);
382   ierr = PetscBLASIntCast(worksize,&ldwork);CHKERRQ(ierr);
383   ierr = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr);
384   LAPACKgeqrf_(&M,&N,A,&lda,tau,work,&ldwork,&info);
385   ierr = PetscFPTrapPop();CHKERRQ(ierr);
386   if (info) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"xGEQRF error");
387   R = A; /* Upper triangular part of A now contains R, the rest contains the elementary reflectors */
388 
389   /* Extract an explicit representation of Q */
390   Q = Ainv;
391   ierr = PetscMemcpy(Q,A,mstride*n*sizeof(PetscScalar));CHKERRQ(ierr);
392   K = N;                        /* full rank */
393   LAPACKungqr_(&M,&N,&K,Q,&lda,tau,work,&ldwork,&info);
394   if (info) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"xORGQR/xUNGQR error");
395 
396   /* Compute A^{-T} = (R^{-1} Q^T)^T = Q R^{-T} */
397   Alpha = 1.0;
398   ldb = lda;
399   BLAStrsm_("Right","Upper","ConjugateTranspose","NotUnitTriangular",&M,&N,&Alpha,R,&lda,Q,&ldb);
400   /* Ainv is Q, overwritten with inverse */
401 
402 #if defined(PETSC_USE_COMPLEX)
403   {
404     PetscInt i;
405     for (i=0; i<m*n; i++) Ainv_out[i] = PetscRealPart(Ainv[i]);
406     ierr = PetscFree2(A,Ainv);CHKERRQ(ierr);
407   }
408 #endif
409   PetscFunctionReturn(0);
410 }
411 
412 #undef __FUNCT__
413 #define __FUNCT__ "PetscDTLegendreIntegrate"
414 /* Computes integral of L_p' over intervals {(x0,x1),(x1,x2),...} */
415 static PetscErrorCode PetscDTLegendreIntegrate(PetscInt ninterval,const PetscReal *x,PetscInt ndegree,const PetscInt *degrees,PetscBool Transpose,PetscReal *B)
416 {
417   PetscErrorCode ierr;
418   PetscReal *Bv;
419   PetscInt i,j;
420 
421   PetscFunctionBegin;
422   ierr = PetscMalloc((ninterval+1)*ndegree*sizeof(PetscReal),&Bv);CHKERRQ(ierr);
423   /* Point evaluation of L_p on all the source vertices */
424   ierr = PetscDTLegendreEval(ninterval+1,x,ndegree,degrees,Bv,NULL,NULL);CHKERRQ(ierr);
425   /* Integral over each interval: \int_a^b L_p' = L_p(b)-L_p(a) */
426   for (i=0; i<ninterval; i++) {
427     for (j=0; j<ndegree; j++) {
428       if (Transpose) B[i+ninterval*j] = Bv[(i+1)*ndegree+j] - Bv[i*ndegree+j];
429       else           B[i*ndegree+j]   = Bv[(i+1)*ndegree+j] - Bv[i*ndegree+j];
430     }
431   }
432   ierr = PetscFree(Bv);CHKERRQ(ierr);
433   PetscFunctionReturn(0);
434 }
435 
436 #undef __FUNCT__
437 #define __FUNCT__ "PetscDTReconstructPoly"
438 /*@
439    PetscDTReconstructPoly - create matrix representing polynomial reconstruction using cell intervals and evaluation at target intervals
440 
441    Not Collective
442 
443    Input Arguments:
444 +  degree - degree of reconstruction polynomial
445 .  nsource - number of source intervals
446 .  sourcex - sorted coordinates of source cell boundaries (length nsource+1)
447 .  ntarget - number of target intervals
448 -  targetx - sorted coordinates of target cell boundaries (length ntarget+1)
449 
450    Output Arguments:
451 .  R - reconstruction matrix, utarget = sum_s R[t*nsource+s] * usource[s]
452 
453    Level: advanced
454 
455 .seealso: PetscDTLegendreEval()
456 @*/
457 PetscErrorCode PetscDTReconstructPoly(PetscInt degree,PetscInt nsource,const PetscReal *sourcex,PetscInt ntarget,const PetscReal *targetx,PetscReal *R)
458 {
459   PetscErrorCode ierr;
460   PetscInt i,j,k,*bdegrees,worksize;
461   PetscReal xmin,xmax,center,hscale,*sourcey,*targety,*Bsource,*Bsinv,*Btarget;
462   PetscScalar *tau,*work;
463 
464   PetscFunctionBegin;
465   PetscValidRealPointer(sourcex,3);
466   PetscValidRealPointer(targetx,5);
467   PetscValidRealPointer(R,6);
468   if (degree >= nsource) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Reconstruction degree %D must be less than number of source intervals %D",degree,nsource);
469 #if defined(PETSC_USE_DEBUG)
470   for (i=0; i<nsource; i++) {
471     if (sourcex[i] >= sourcex[i+1]) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_CORRUPT,"Source interval %D has negative orientation (%G,%G)",i,sourcex[i],sourcex[i+1]);
472   }
473   for (i=0; i<ntarget; i++) {
474     if (targetx[i] >= targetx[i+1]) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_CORRUPT,"Target interval %D has negative orientation (%G,%G)",i,targetx[i],targetx[i+1]);
475   }
476 #endif
477   xmin = PetscMin(sourcex[0],targetx[0]);
478   xmax = PetscMax(sourcex[nsource],targetx[ntarget]);
479   center = (xmin + xmax)/2;
480   hscale = (xmax - xmin)/2;
481   worksize = nsource;
482   ierr = PetscMalloc4(degree+1,PetscInt,&bdegrees,nsource+1,PetscReal,&sourcey,nsource*(degree+1),PetscReal,&Bsource,worksize,PetscScalar,&work);CHKERRQ(ierr);
483   ierr = PetscMalloc4(nsource,PetscScalar,&tau,nsource*(degree+1),PetscReal,&Bsinv,ntarget+1,PetscReal,&targety,ntarget*(degree+1),PetscReal,&Btarget);CHKERRQ(ierr);
484   for (i=0; i<=nsource; i++) sourcey[i] = (sourcex[i]-center)/hscale;
485   for (i=0; i<=degree; i++) bdegrees[i] = i+1;
486   ierr = PetscDTLegendreIntegrate(nsource,sourcey,degree+1,bdegrees,PETSC_TRUE,Bsource);CHKERRQ(ierr);
487   ierr = PetscDTPseudoInverseQR(nsource,nsource,degree+1,Bsource,Bsinv,tau,nsource,work);CHKERRQ(ierr);
488   for (i=0; i<=ntarget; i++) targety[i] = (targetx[i]-center)/hscale;
489   ierr = PetscDTLegendreIntegrate(ntarget,targety,degree+1,bdegrees,PETSC_FALSE,Btarget);CHKERRQ(ierr);
490   for (i=0; i<ntarget; i++) {
491     PetscReal rowsum = 0;
492     for (j=0; j<nsource; j++) {
493       PetscReal sum = 0;
494       for (k=0; k<degree+1; k++) {
495         sum += Btarget[i*(degree+1)+k] * Bsinv[k*nsource+j];
496       }
497       R[i*nsource+j] = sum;
498       rowsum += sum;
499     }
500     for (j=0; j<nsource; j++) R[i*nsource+j] /= rowsum; /* normalize each row */
501   }
502   ierr = PetscFree4(bdegrees,sourcey,Bsource,work);CHKERRQ(ierr);
503   ierr = PetscFree4(tau,Bsinv,targety,Btarget);CHKERRQ(ierr);
504   PetscFunctionReturn(0);
505 }
506 
507 /* Basis Jet Tabulation
508 
509 We would like to tabulate the nodal basis functions and derivatives at a set of points, usually quadrature points. We
510 follow here the derviation in http://www.math.ttu.edu/~kirby/papers/fiat-toms-2004.pdf. The nodal basis $\psi_i$ can
511 be expressed in terms of a prime basis $\phi_i$ which can be stably evaluated. In PETSc, we will use the Legendre basis
512 as a prime basis.
513 
514   \psi_i = \sum_k \alpha_{ki} \phi_k
515 
516 Our nodal basis is defined in terms of the dual basis $n_j$
517 
518   n_j \cdot \psi_i = \delta_{ji}
519 
520 and we may act on the first equation to obtain
521 
522   n_j \cdot \psi_i = \sum_k \alpha_{ki} n_j \cdot \phi_k
523        \delta_{ji} = \sum_k \alpha_{ki} V_{jk}
524                  I = V \alpha
525 
526 so the coefficients of the nodal basis in the prime basis are
527 
528    \alpha = V^{-1}
529 
530 We will define the dual basis vectors $n_j$ using a quadrature rule.
531 
532 Right now, we will just use the polynomial spaces P^k. I know some elements use the space of symmetric polynomials
533 (I think Nedelec), but we will neglect this for now. Constraints in the space, e.g. Arnold-Winther elements, can
534 be implemented exactly as in FIAT using functionals $L_j$.
535 
536 I will have to count the degrees correctly for the Legendre product when we are on simplices.
537 
538 We will have three objects:
539  - Space, P: this just need point evaluation I think
540  - Dual Space, P'+K: This looks like a set of functionals that can act on members of P, each n is defined by a Q
541  - FEM: This keeps {P, P', Q}
542 */
543 #include <petsc-private/petscfeimpl.h>
544 
545 PetscInt PETSCSPACE_CLASSID = 0;
546 
547 PetscFunctionList PetscSpaceList              = NULL;
548 PetscBool         PetscSpaceRegisterAllCalled = PETSC_FALSE;
549 
550 #undef __FUNCT__
551 #define __FUNCT__ "PetscSpaceRegister"
552 /*@C
553   PetscSpaceRegister - Adds a new PetscSpace implementation
554 
555   Not Collective
556 
557   Input Parameters:
558 + name        - The name of a new user-defined creation routine
559 - create_func - The creation routine itself
560 
561   Notes:
562   PetscSpaceRegister() may be called multiple times to add several user-defined PetscSpaces
563 
564   Sample usage:
565 .vb
566     PetscSpaceRegister("my_space", MyPetscSpaceCreate);
567 .ve
568 
569   Then, your PetscSpace type can be chosen with the procedural interface via
570 .vb
571     PetscSpaceCreate(MPI_Comm, PetscSpace *);
572     PetscSpaceSetType(PetscSpace, "my_space");
573 .ve
574    or at runtime via the option
575 .vb
576     -petscspace_type my_space
577 .ve
578 
579   Level: advanced
580 
581 .keywords: PetscSpace, register
582 .seealso: PetscSpaceRegisterAll(), PetscSpaceRegisterDestroy()
583 
584 @*/
585 PetscErrorCode PetscSpaceRegister(const char sname[], PetscErrorCode (*function)(PetscSpace))
586 {
587   PetscErrorCode ierr;
588 
589   PetscFunctionBegin;
590   ierr = PetscFunctionListAdd(&PetscSpaceList, sname, function);CHKERRQ(ierr);
591   PetscFunctionReturn(0);
592 }
593 
594 #undef __FUNCT__
595 #define __FUNCT__ "PetscSpaceSetType"
596 /*@C
597   PetscSpaceSetType - Builds a particular PetscSpace
598 
599   Collective on PetscSpace
600 
601   Input Parameters:
602 + sp   - The PetscSpace object
603 - name - The kind of space
604 
605   Options Database Key:
606 . -petscspace_type <type> - Sets the PetscSpace type; use -help for a list of available types
607 
608   Level: intermediate
609 
610 .keywords: PetscSpace, set, type
611 .seealso: PetscSpaceGetType(), PetscSpaceCreate()
612 @*/
613 PetscErrorCode PetscSpaceSetType(PetscSpace sp, PetscSpaceType name)
614 {
615   PetscErrorCode (*r)(PetscSpace);
616   PetscBool      match;
617   PetscErrorCode ierr;
618 
619   PetscFunctionBegin;
620   PetscValidHeaderSpecific(sp, PETSCSPACE_CLASSID, 1);
621   ierr = PetscObjectTypeCompare((PetscObject) sp, name, &match);CHKERRQ(ierr);
622   if (match) PetscFunctionReturn(0);
623 
624   if (!PetscSpaceRegisterAllCalled) {ierr = PetscSpaceRegisterAll();CHKERRQ(ierr);}
625   ierr = PetscFunctionListFind(PetscSpaceList, name, &r);CHKERRQ(ierr);
626   if (!r) SETERRQ1(PetscObjectComm((PetscObject) sp), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscSpace type: %s", name);
627 
628   if (sp->ops->destroy) {
629     ierr             = (*sp->ops->destroy)(sp);CHKERRQ(ierr);
630     sp->ops->destroy = NULL;
631   }
632   ierr = (*r)(sp);CHKERRQ(ierr);
633   ierr = PetscObjectChangeTypeName((PetscObject) sp, name);CHKERRQ(ierr);
634   PetscFunctionReturn(0);
635 }
636 
637 #undef __FUNCT__
638 #define __FUNCT__ "PetscSpaceGetType"
639 /*@C
640   PetscSpaceGetType - Gets the PetscSpace type name (as a string) from the object.
641 
642   Not Collective
643 
644   Input Parameter:
645 . dm  - The PetscSpace
646 
647   Output Parameter:
648 . name - The PetscSpace type name
649 
650   Level: intermediate
651 
652 .keywords: PetscSpace, get, type, name
653 .seealso: PetscSpaceSetType(), PetscSpaceCreate()
654 @*/
655 PetscErrorCode PetscSpaceGetType(PetscSpace sp, PetscSpaceType *name)
656 {
657   PetscErrorCode ierr;
658 
659   PetscFunctionBegin;
660   PetscValidHeaderSpecific(sp, PETSCSPACE_CLASSID, 1);
661   PetscValidCharPointer(name, 2);
662   if (!PetscSpaceRegisterAllCalled) {
663     ierr = PetscSpaceRegisterAll();CHKERRQ(ierr);
664   }
665   *name = ((PetscObject) sp)->type_name;
666   PetscFunctionReturn(0);
667 }
668 
669 #undef __FUNCT__
670 #define __FUNCT__ "PetscSpaceView"
671 /*@C
672   PetscSpaceView - Views a PetscSpace
673 
674   Collective on PetscSpace
675 
676   Input Parameter:
677 + sp - the PetscSpace object to view
678 - v  - the viewer
679 
680   Level: developer
681 
682 .seealso PetscSpaceDestroy()
683 @*/
684 PetscErrorCode PetscSpaceView(PetscSpace sp, PetscViewer v)
685 {
686   PetscErrorCode ierr;
687 
688   PetscFunctionBegin;
689   PetscValidHeaderSpecific(sp, PETSCSPACE_CLASSID, 1);
690   if (!v) {
691     ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject) sp), &v);CHKERRQ(ierr);
692   }
693   if (sp->ops->view) {
694     ierr = (*sp->ops->view)(sp, v);CHKERRQ(ierr);
695   }
696   PetscFunctionReturn(0);
697 }
698 
699 #undef __FUNCT__
700 #define __FUNCT__ "PetscSpaceViewFromOptions"
701 /*
702   PetscSpaceViewFromOptions - Processes command line options to determine if/how a PetscSpace is to be viewed.
703 
704   Collective on PetscSpace
705 
706   Input Parameters:
707 + sp   - the PetscSpace
708 . prefix - prefix to use for viewing, or NULL to use prefix of 'rnd'
709 - optionname - option to activate viewing
710 
711   Level: intermediate
712 
713 .keywords: PetscSpace, view, options, database
714 .seealso: VecViewFromOptions(), MatViewFromOptions()
715 */
716 PetscErrorCode PetscSpaceViewFromOptions(PetscSpace sp, const char prefix[], const char optionname[])
717 {
718   PetscViewer       viewer;
719   PetscViewerFormat format;
720   PetscBool         flg;
721   PetscErrorCode    ierr;
722 
723   PetscFunctionBegin;
724   if (prefix) {
725     ierr = PetscOptionsGetViewer(PetscObjectComm((PetscObject) sp), prefix, optionname, &viewer, &format, &flg);CHKERRQ(ierr);
726   } else {
727     ierr = PetscOptionsGetViewer(PetscObjectComm((PetscObject) sp), ((PetscObject) sp)->prefix, optionname, &viewer, &format, &flg);CHKERRQ(ierr);
728   }
729   if (flg) {
730     ierr = PetscViewerPushFormat(viewer, format);CHKERRQ(ierr);
731     ierr = PetscSpaceView(sp, viewer);CHKERRQ(ierr);
732     ierr = PetscViewerPopFormat(viewer);CHKERRQ(ierr);
733     ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
734   }
735   PetscFunctionReturn(0);
736 }
737 
738 #undef __FUNCT__
739 #define __FUNCT__ "PetscSpaceSetFromOptions"
740 /*@
741   PetscSpaceSetFromOptions - sets parameters in a PetscSpace from the options database
742 
743   Collective on PetscSpace
744 
745   Input Parameter:
746 . sp - the PetscSpace object to set options for
747 
748   Options Database:
749 . -petscspace_order the approximation order of the space
750 
751   Level: developer
752 
753 .seealso PetscSpaceView()
754 @*/
755 PetscErrorCode PetscSpaceSetFromOptions(PetscSpace sp)
756 {
757   const char    *defaultType;
758   char           typename[256];
759   PetscBool      flg;
760   PetscErrorCode ierr;
761 
762   PetscFunctionBegin;
763   PetscValidHeaderSpecific(sp, PETSCSPACE_CLASSID, 1);
764   if (!((PetscObject) sp)->type_name) {
765     defaultType = PETSCSPACEPOLYNOMIAL;
766   } else {
767     defaultType = ((PetscObject) sp)->type_name;
768   }
769   if (!PetscSpaceRegisterAllCalled) {ierr = PetscSpaceRegisterAll();CHKERRQ(ierr);}
770 
771   ierr = PetscObjectOptionsBegin((PetscObject) sp);CHKERRQ(ierr);
772   ierr = PetscOptionsList("-petscspace_type", "Linear space", "PetscSpaceSetType", PetscSpaceList, defaultType, typename, 256, &flg);CHKERRQ(ierr);
773   if (flg) {
774     ierr = PetscSpaceSetType(sp, typename);CHKERRQ(ierr);
775   } else if (!((PetscObject) sp)->type_name) {
776     ierr = PetscSpaceSetType(sp, defaultType);CHKERRQ(ierr);
777   }
778   ierr = PetscOptionsInt("-petscspace_order", "The approximation order", "PetscSpaceSetOrder", sp->order, &sp->order, NULL);CHKERRQ(ierr);
779   if (sp->ops->setfromoptions) {
780     ierr = (*sp->ops->setfromoptions)(sp);CHKERRQ(ierr);
781   }
782   /* process any options handlers added with PetscObjectAddOptionsHandler() */
783   ierr = PetscObjectProcessOptionsHandlers((PetscObject) sp);CHKERRQ(ierr);
784   ierr = PetscOptionsEnd();CHKERRQ(ierr);
785   ierr = PetscSpaceViewFromOptions(sp, NULL, "-petscspace_view");CHKERRQ(ierr);
786   PetscFunctionReturn(0);
787 }
788 
789 #undef __FUNCT__
790 #define __FUNCT__ "PetscSpaceSetUp"
791 /*@C
792   PetscSpaceSetUp - Construct data structures for the PetscSpace
793 
794   Collective on PetscSpace
795 
796   Input Parameter:
797 . sp - the PetscSpace object to setup
798 
799   Level: developer
800 
801 .seealso PetscSpaceView(), PetscSpaceDestroy()
802 @*/
803 PetscErrorCode PetscSpaceSetUp(PetscSpace sp)
804 {
805   PetscErrorCode ierr;
806 
807   PetscFunctionBegin;
808   PetscValidHeaderSpecific(sp, PETSCSPACE_CLASSID, 1);
809   if (sp->ops->setup) {ierr = (*sp->ops->setup)(sp);CHKERRQ(ierr);}
810   PetscFunctionReturn(0);
811 }
812 
813 #undef __FUNCT__
814 #define __FUNCT__ "PetscSpaceDestroy"
815 /*@
816   PetscSpaceDestroy - Destroys a PetscSpace object
817 
818   Collective on PetscSpace
819 
820   Input Parameter:
821 . sp - the PetscSpace object to destroy
822 
823   Level: developer
824 
825 .seealso PetscSpaceView()
826 @*/
827 PetscErrorCode PetscSpaceDestroy(PetscSpace *sp)
828 {
829   PetscErrorCode ierr;
830 
831   PetscFunctionBegin;
832   if (!*sp) PetscFunctionReturn(0);
833   PetscValidHeaderSpecific((*sp), PETSCSPACE_CLASSID, 1);
834 
835   if (--((PetscObject)(*sp))->refct > 0) {*sp = 0; PetscFunctionReturn(0);}
836   ((PetscObject) (*sp))->refct = 0;
837   /* if memory was published with AMS then destroy it */
838   ierr = PetscObjectAMSViewOff((PetscObject) *sp);CHKERRQ(ierr);
839 
840   ierr = DMDestroy(&(*sp)->dm);CHKERRQ(ierr);
841 
842   ierr = (*(*sp)->ops->destroy)(*sp);CHKERRQ(ierr);
843   ierr = PetscHeaderDestroy(sp);CHKERRQ(ierr);
844   PetscFunctionReturn(0);
845 }
846 
847 #undef __FUNCT__
848 #define __FUNCT__ "PetscSpaceCreate"
849 /*@
850   PetscSpaceCreate - Creates an empty PetscSpace object. The type can then be set with PetscSpaceSetType().
851 
852   Collective on MPI_Comm
853 
854   Input Parameter:
855 . comm - The communicator for the PetscSpace object
856 
857   Output Parameter:
858 . sp - The PetscSpace object
859 
860   Level: beginner
861 
862 .seealso: PetscSpaceSetType(), PETSCSPACEPOLYNOMIAL
863 @*/
864 PetscErrorCode PetscSpaceCreate(MPI_Comm comm, PetscSpace *sp)
865 {
866   PetscSpace     s;
867   PetscErrorCode ierr;
868 
869   PetscFunctionBegin;
870   PetscValidPointer(sp, 2);
871   *sp = NULL;
872 #if !defined(PETSC_USE_DYNAMIC_LIBRARIES)
873   ierr = PetscFEInitializePackage();CHKERRQ(ierr);
874 #endif
875 
876   ierr = PetscHeaderCreate(s, _p_PetscSpace, struct _PetscSpaceOps, PETSCSPACE_CLASSID, "PetscSpace", "Linear Space", "PetscSpace", comm, PetscSpaceDestroy, PetscSpaceView);CHKERRQ(ierr);
877   ierr = PetscMemzero(s->ops, sizeof(struct _PetscSpaceOps));CHKERRQ(ierr);
878 
879   s->order = 0;
880   ierr = DMShellCreate(comm, &s->dm);CHKERRQ(ierr);
881 
882   *sp = s;
883   PetscFunctionReturn(0);
884 }
885 
886 #undef __FUNCT__
887 #define __FUNCT__ "PetscSpaceGetDimension"
888 /* Dimension of the space, i.e. number of basis vectors */
889 PetscErrorCode PetscSpaceGetDimension(PetscSpace sp, PetscInt *dim)
890 {
891   PetscErrorCode ierr;
892 
893   PetscFunctionBegin;
894   PetscValidHeaderSpecific(sp, PETSCSPACE_CLASSID, 1);
895   PetscValidPointer(dim, 2);
896   *dim = 0;
897   if (sp->ops->getdimension) {ierr = (*sp->ops->getdimension)(sp, dim);CHKERRQ(ierr);}
898   PetscFunctionReturn(0);
899 }
900 
901 #undef __FUNCT__
902 #define __FUNCT__ "PetscSpaceGetOrder"
903 PetscErrorCode PetscSpaceGetOrder(PetscSpace sp, PetscInt *order)
904 {
905   PetscFunctionBegin;
906   PetscValidHeaderSpecific(sp, PETSCSPACE_CLASSID, 1);
907   PetscValidPointer(order, 2);
908   *order = sp->order;
909   PetscFunctionReturn(0);
910 }
911 
912 #undef __FUNCT__
913 #define __FUNCT__ "PetscSpaceSetOrder"
914 PetscErrorCode PetscSpaceSetOrder(PetscSpace sp, PetscInt order)
915 {
916   PetscFunctionBegin;
917   PetscValidHeaderSpecific(sp, PETSCSPACE_CLASSID, 1);
918   sp->order = order;
919   PetscFunctionReturn(0);
920 }
921 
922 #undef __FUNCT__
923 #define __FUNCT__ "PetscSpaceEvaluate"
924 PetscErrorCode PetscSpaceEvaluate(PetscSpace sp, PetscInt npoints, const PetscReal points[], PetscReal B[], PetscReal D[], PetscReal H[])
925 {
926   PetscErrorCode ierr;
927 
928   PetscFunctionBegin;
929   PetscValidHeaderSpecific(sp, PETSCSPACE_CLASSID, 1);
930   PetscValidPointer(points, 3);
931   if (B) PetscValidPointer(B, 4);
932   if (D) PetscValidPointer(D, 5);
933   if (H) PetscValidPointer(H, 6);
934   if (sp->ops->evaluate) {ierr = (*sp->ops->evaluate)(sp, npoints, points, B, D, H);CHKERRQ(ierr);}
935   PetscFunctionReturn(0);
936 }
937 
938 #undef __FUNCT__
939 #define __FUNCT__ "PetscSpaceSetFromOptions_Polynomial"
940 PetscErrorCode PetscSpaceSetFromOptions_Polynomial(PetscSpace sp)
941 {
942   PetscSpace_Poly *poly = (PetscSpace_Poly *) sp->data;
943   PetscErrorCode   ierr;
944 
945   PetscFunctionBegin;
946   ierr = PetscObjectOptionsBegin((PetscObject) sp);CHKERRQ(ierr);
947   ierr = PetscOptionsInt("-petscspace_num_variables", "The number of different variables, e.g. x and y", "PetscSpacePolynomialSetNumVariables", poly->numVariables, &poly->numVariables, NULL);CHKERRQ(ierr);
948   ierr = PetscOptionsBool("-petscspace_poly_sym", "Use only symmetric polynomials", "PetscSpacePolynomialSetSymmetric", poly->symmetric, &poly->symmetric, NULL);CHKERRQ(ierr);
949   ierr = PetscOptionsEnd();CHKERRQ(ierr);
950   PetscFunctionReturn(0);
951 }
952 
953 #undef __FUNCT__
954 #define __FUNCT__ "PetscSpacePolynomialView_Ascii"
955 PetscErrorCode PetscSpacePolynomialView_Ascii(PetscSpace sp, PetscViewer viewer)
956 {
957   PetscSpace_Poly  *poly = (PetscSpace_Poly *) sp->data;
958   PetscViewerFormat format;
959   PetscErrorCode    ierr;
960 
961   PetscFunctionBegin;
962   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
963   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
964     ierr = PetscViewerASCIIPrintf(viewer, "Polynomial space in %d variables of order %d", poly->numVariables, sp->order);CHKERRQ(ierr);
965   } else {
966     ierr = PetscViewerASCIIPrintf(viewer, "Polynomial space in %d variables of order %d", poly->numVariables, sp->order);CHKERRQ(ierr);
967   }
968   PetscFunctionReturn(0);
969 }
970 
971 #undef __FUNCT__
972 #define __FUNCT__ "PetscSpaceView_Polynomial"
973 PetscErrorCode PetscSpaceView_Polynomial(PetscSpace sp, PetscViewer viewer)
974 {
975   PetscBool      iascii;
976   PetscErrorCode ierr;
977 
978   PetscFunctionBegin;
979   PetscValidHeaderSpecific(sp, PETSCSPACE_CLASSID, 1);
980   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
981   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
982   if (iascii) {ierr = PetscSpacePolynomialView_Ascii(sp, viewer);CHKERRQ(ierr);}
983   PetscFunctionReturn(0);
984 }
985 
986 #undef __FUNCT__
987 #define __FUNCT__ "PetscSpaceSetUp_Polynomial"
988 PetscErrorCode PetscSpaceSetUp_Polynomial(PetscSpace sp)
989 {
990   PetscSpace_Poly *poly    = (PetscSpace_Poly *) sp->data;
991   PetscInt         ndegree = sp->order+1;
992   PetscInt         deg;
993   PetscErrorCode   ierr;
994 
995   PetscFunctionBegin;
996   ierr = PetscMalloc(ndegree * sizeof(PetscInt), &poly->degrees);CHKERRQ(ierr);
997   for (deg = 0; deg < ndegree; ++deg) poly->degrees[deg] = deg;
998   PetscFunctionReturn(0);
999 }
1000 
1001 #undef __FUNCT__
1002 #define __FUNCT__ "PetscSpaceDestroy_Polynomial"
1003 PetscErrorCode PetscSpaceDestroy_Polynomial(PetscSpace sp)
1004 {
1005   PetscSpace_Poly *poly = (PetscSpace_Poly *) sp->data;
1006   PetscErrorCode   ierr;
1007 
1008   PetscFunctionBegin;
1009   ierr = PetscFree(poly->degrees);CHKERRQ(ierr);
1010   ierr = PetscFree(poly);CHKERRQ(ierr);
1011   PetscFunctionReturn(0);
1012 }
1013 
1014 #undef __FUNCT__
1015 #define __FUNCT__ "PetscSpaceGetDimension_Polynomial"
1016 PetscErrorCode PetscSpaceGetDimension_Polynomial(PetscSpace sp, PetscInt *dim)
1017 {
1018   PetscSpace_Poly *poly = (PetscSpace_Poly *) sp->data;
1019   PetscInt         deg  = sp->order;
1020   PetscInt         n    = poly->numVariables, i;
1021   PetscReal        D    = 1.0;
1022 
1023   PetscFunctionBegin;
1024   for (i = 1; i <= n; ++i) {
1025     D *= ((PetscReal) (deg+i))/i;
1026   }
1027   *dim = (PetscInt) (D + 0.5);
1028   PetscFunctionReturn(0);
1029 }
1030 
1031 #undef __FUNCT__
1032 #define __FUNCT__ "LatticePoint_Internal"
1033 /*
1034   LatticePoint_Internal - Returns all tuples of size 'len' with nonnegative integers that sum up to 'sum'.
1035 
1036   Input Parameters:
1037 + len - The length of the tuple
1038 . sum - The sum of all entries in the tuple
1039 - ind - The current multi-index of the tuple, initialized to the 0 tuple
1040 
1041   Output Parameter:
1042 + ind - The multi-index of the tuple, -1 indicates the iteration has terminated
1043 . tup - A tuple of len integers addig to sum
1044 
1045   Level: developer
1046 
1047 .seealso:
1048 */
1049 static PetscErrorCode LatticePoint_Internal(PetscInt len, PetscInt sum, PetscInt ind[], PetscInt tup[])
1050 {
1051   PetscInt       i;
1052   PetscErrorCode ierr;
1053 
1054   PetscFunctionBegin;
1055   if (len == 1) {
1056     ind[0] = -1;
1057     tup[0] = sum;
1058   } else if (sum == 0) {
1059     for (i = 0; i < len; ++i) {ind[0] = -1; tup[i] = 0;}
1060   } else {
1061     tup[0] = sum - ind[0];
1062     ierr = LatticePoint_Internal(len-1, ind[0], &ind[1], &tup[1]);CHKERRQ(ierr);
1063     if (ind[1] < 0) {
1064       if (ind[0] == sum) {ind[0] = -1;}
1065       else               {ind[1] = 0; ++ind[0];}
1066     }
1067   }
1068   PetscFunctionReturn(0);
1069 }
1070 
1071 #undef __FUNCT__
1072 #define __FUNCT__ "PetscSpaceEvaluate_Polynomial"
1073 PetscErrorCode PetscSpaceEvaluate_Polynomial(PetscSpace sp, PetscInt npoints, const PetscReal points[], PetscReal B[], PetscReal D[], PetscReal H[])
1074 {
1075   PetscSpace_Poly *poly    = (PetscSpace_Poly *) sp->data;
1076   DM               dm      = sp->dm;
1077   PetscInt         ndegree = sp->order+1;
1078   PetscInt        *degrees = poly->degrees;
1079   PetscInt         dim     = poly->numVariables;
1080   PetscReal       *lpoints, *tmp, *LB, *LD, *LH;
1081   PetscInt        *ind, *tup;
1082   PetscInt         pdim, d, i, p, deg, o;
1083   PetscErrorCode   ierr;
1084 
1085   PetscFunctionBegin;
1086   ierr = PetscSpaceGetDimension(sp, &pdim);CHKERRQ(ierr);
1087   ierr = DMGetWorkArray(dm, npoints, PETSC_REAL, &lpoints);CHKERRQ(ierr);
1088   ierr = DMGetWorkArray(dm, npoints*ndegree*3, PETSC_REAL, &tmp);CHKERRQ(ierr);
1089   if (B) {ierr = DMGetWorkArray(dm, npoints*dim*ndegree, PETSC_REAL, &LB);CHKERRQ(ierr);}
1090   if (D) {ierr = DMGetWorkArray(dm, npoints*dim*ndegree, PETSC_REAL, &LD);CHKERRQ(ierr);}
1091   if (H) {ierr = DMGetWorkArray(dm, npoints*dim*ndegree, PETSC_REAL, &LH);CHKERRQ(ierr);}
1092   for (d = 0; d < dim; ++d) {
1093     for (p = 0; p < npoints; ++p) {
1094       lpoints[p] = points[p*dim+d];
1095     }
1096     ierr = PetscDTLegendreEval(npoints, lpoints, ndegree, degrees, tmp, &tmp[1*npoints*ndegree], &tmp[2*npoints*ndegree]);CHKERRQ(ierr);
1097     /* LB, LD, LH (ndegree * dim x npoints) */
1098     for (deg = 0; deg < ndegree; ++deg) {
1099       for (p = 0; p < npoints; ++p) {
1100         if (B) LB[(deg*dim + d)*npoints + p] = tmp[(0*npoints + p)*ndegree+deg];
1101         if (D) LD[(deg*dim + d)*npoints + p] = tmp[(1*npoints + p)*ndegree+deg];
1102         if (H) LH[(deg*dim + d)*npoints + p] = tmp[(2*npoints + p)*ndegree+deg];
1103       }
1104     }
1105   }
1106   /* Multiply by A (pdim x ndegree * dim) */
1107   ierr = PetscMalloc2(dim,PetscInt,&ind,dim,PetscInt,&tup);CHKERRQ(ierr);
1108   if (B) {
1109     /* B (npoints x pdim) */
1110     i = 0;
1111     for (o = 0; o <= sp->order; ++o) {
1112       ierr = PetscMemzero(ind, dim * sizeof(PetscInt));CHKERRQ(ierr);
1113       while (ind[0] >= 0) {
1114         ierr = LatticePoint_Internal(dim, o, ind, tup);CHKERRQ(ierr);
1115         for (p = 0; p < npoints; ++p) {
1116           B[p*pdim + i] = 1.0;
1117           for (d = 0; d < dim; ++d) {
1118             B[p*pdim + i] *= LB[(tup[d]*dim + d)*npoints + p];
1119           }
1120         }
1121         ++i;
1122       }
1123     }
1124   }
1125   ierr = PetscFree2(ind,tup);CHKERRQ(ierr);
1126   if (D) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Too lazy to code first derivatives");
1127   if (H) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Too lazy to code second derivatives");
1128   if (B) {ierr = DMRestoreWorkArray(dm, npoints*dim*ndegree, PETSC_REAL, &LB);CHKERRQ(ierr);}
1129   if (D) {ierr = DMRestoreWorkArray(dm, npoints*dim*ndegree, PETSC_REAL, &LD);CHKERRQ(ierr);}
1130   if (H) {ierr = DMRestoreWorkArray(dm, npoints*dim*ndegree, PETSC_REAL, &LH);CHKERRQ(ierr);}
1131   ierr = DMRestoreWorkArray(dm, npoints*ndegree*3, PETSC_REAL, &tmp);CHKERRQ(ierr);
1132   ierr = DMRestoreWorkArray(dm, npoints, PETSC_REAL, &lpoints);CHKERRQ(ierr);
1133   PetscFunctionReturn(0);
1134 }
1135 
1136 #undef __FUNCT__
1137 #define __FUNCT__ "PetscSpaceInitialize_Polynomial"
1138 PetscErrorCode PetscSpaceInitialize_Polynomial(PetscSpace sp)
1139 {
1140   PetscFunctionBegin;
1141   sp->ops->setfromoptions = PetscSpaceSetFromOptions_Polynomial;
1142   sp->ops->setup          = PetscSpaceSetUp_Polynomial;
1143   sp->ops->view           = PetscSpaceView_Polynomial;
1144   sp->ops->destroy        = PetscSpaceDestroy_Polynomial;
1145   sp->ops->getdimension   = PetscSpaceGetDimension_Polynomial;
1146   sp->ops->evaluate       = PetscSpaceEvaluate_Polynomial;
1147   PetscFunctionReturn(0);
1148 }
1149 
1150 /*MC
1151   PETSCSPACEPOLYNOMIAL = "poly" - A PetscSpace object that encapsulates a polynomial space, e.g. P1 is the space of linear polynomials.
1152 
1153   Level: intermediate
1154 
1155 .seealso: PetscSpaceType, PetscSpaceCreate(), PetscSpaceSetType()
1156 M*/
1157 
1158 #undef __FUNCT__
1159 #define __FUNCT__ "PetscSpaceCreate_Polynomial"
1160 PETSC_EXTERN PetscErrorCode PetscSpaceCreate_Polynomial(PetscSpace sp)
1161 {
1162   PetscSpace_Poly *poly;
1163   PetscErrorCode   ierr;
1164 
1165   PetscFunctionBegin;
1166   PetscValidHeaderSpecific(sp, PETSCSPACE_CLASSID, 1);
1167   ierr     = PetscNewLog(sp, PetscSpace_Poly, &poly);CHKERRQ(ierr);
1168   sp->data = poly;
1169 
1170   poly->numVariables = 0;
1171   poly->symmetric    = PETSC_FALSE;
1172   poly->degrees      = NULL;
1173 
1174   ierr = PetscSpaceInitialize_Polynomial(sp);CHKERRQ(ierr);
1175   PetscFunctionReturn(0);
1176 }
1177 
1178 #undef __FUNCT__
1179 #define __FUNCT__ "PetscSpacePolynomialSetSymmetric"
1180 PetscErrorCode PetscSpacePolynomialSetSymmetric(PetscSpace sp, PetscBool sym)
1181 {
1182   PetscSpace_Poly *poly = (PetscSpace_Poly *) sp->data;
1183 
1184   PetscFunctionBegin;
1185   PetscValidHeaderSpecific(sp, PETSCSPACE_CLASSID, 1);
1186   poly->symmetric = sym;
1187   PetscFunctionReturn(0);
1188 }
1189 
1190 #undef __FUNCT__
1191 #define __FUNCT__ "PetscSpacePolynomialGetSymmetric"
1192 PetscErrorCode PetscSpacePolynomialGetSymmetric(PetscSpace sp, PetscBool *sym)
1193 {
1194   PetscSpace_Poly *poly = (PetscSpace_Poly *) sp->data;
1195 
1196   PetscFunctionBegin;
1197   PetscValidHeaderSpecific(sp, PETSCSPACE_CLASSID, 1);
1198   PetscValidPointer(sym, 2);
1199   *sym = poly->symmetric;
1200   PetscFunctionReturn(0);
1201 }
1202 
1203 #undef __FUNCT__
1204 #define __FUNCT__ "PetscSpacePolynomialSetNumVariables"
1205 PetscErrorCode PetscSpacePolynomialSetNumVariables(PetscSpace sp, PetscInt n)
1206 {
1207   PetscSpace_Poly *poly = (PetscSpace_Poly *) sp->data;
1208 
1209   PetscFunctionBegin;
1210   PetscValidHeaderSpecific(sp, PETSCSPACE_CLASSID, 1);
1211   poly->numVariables = n;
1212   PetscFunctionReturn(0);
1213 }
1214 
1215 #undef __FUNCT__
1216 #define __FUNCT__ "PetscSpacePolynomialGetNumVariables"
1217 PetscErrorCode PetscSpacePolynomialGetNumVariables(PetscSpace sp, PetscInt *n)
1218 {
1219   PetscSpace_Poly *poly = (PetscSpace_Poly *) sp->data;
1220 
1221   PetscFunctionBegin;
1222   PetscValidHeaderSpecific(sp, PETSCSPACE_CLASSID, 1);
1223   PetscValidPointer(n, 2);
1224   *n = poly->numVariables;
1225   PetscFunctionReturn(0);
1226 }
1227 
1228 
1229 PetscInt PETSCDUALSPACE_CLASSID = 0;
1230 
1231 PetscFunctionList PetscDualSpaceList              = NULL;
1232 PetscBool         PetscDualSpaceRegisterAllCalled = PETSC_FALSE;
1233 
1234 #undef __FUNCT__
1235 #define __FUNCT__ "PetscDualSpaceRegister"
1236 /*@C
1237   PetscDualSpaceRegister - Adds a new PetscDualSpace implementation
1238 
1239   Not Collective
1240 
1241   Input Parameters:
1242 + name        - The name of a new user-defined creation routine
1243 - create_func - The creation routine itself
1244 
1245   Notes:
1246   PetscDualSpaceRegister() may be called multiple times to add several user-defined PetscDualSpaces
1247 
1248   Sample usage:
1249 .vb
1250     PetscDualSpaceRegister("my_space", MyPetscDualSpaceCreate);
1251 .ve
1252 
1253   Then, your PetscDualSpace type can be chosen with the procedural interface via
1254 .vb
1255     PetscDualSpaceCreate(MPI_Comm, PetscDualSpace *);
1256     PetscDualSpaceSetType(PetscDualSpace, "my_dual_space");
1257 .ve
1258    or at runtime via the option
1259 .vb
1260     -petscdualspace_type my_dual_space
1261 .ve
1262 
1263   Level: advanced
1264 
1265 .keywords: PetscDualSpace, register
1266 .seealso: PetscDualSpaceRegisterAll(), PetscDualSpaceRegisterDestroy()
1267 
1268 @*/
1269 PetscErrorCode PetscDualSpaceRegister(const char sname[], PetscErrorCode (*function)(PetscDualSpace))
1270 {
1271   PetscErrorCode ierr;
1272 
1273   PetscFunctionBegin;
1274   ierr = PetscFunctionListAdd(&PetscDualSpaceList, sname, function);CHKERRQ(ierr);
1275   PetscFunctionReturn(0);
1276 }
1277 
1278 #undef __FUNCT__
1279 #define __FUNCT__ "PetscDualSpaceSetType"
1280 /*@C
1281   PetscDualSpaceSetType - Builds a particular PetscDualSpace
1282 
1283   Collective on PetscDualSpace
1284 
1285   Input Parameters:
1286 + sp   - The PetscDualSpace object
1287 - name - The kind of space
1288 
1289   Options Database Key:
1290 . -petscdualspace_type <type> - Sets the PetscDualSpace type; use -help for a list of available types
1291 
1292   Level: intermediate
1293 
1294 .keywords: PetscDualSpace, set, type
1295 .seealso: PetscDualSpaceGetType(), PetscDualSpaceCreate()
1296 @*/
1297 PetscErrorCode PetscDualSpaceSetType(PetscDualSpace sp, PetscDualSpaceType name)
1298 {
1299   PetscErrorCode (*r)(PetscDualSpace);
1300   PetscBool      match;
1301   PetscErrorCode ierr;
1302 
1303   PetscFunctionBegin;
1304   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1305   ierr = PetscObjectTypeCompare((PetscObject) sp, name, &match);CHKERRQ(ierr);
1306   if (match) PetscFunctionReturn(0);
1307 
1308   if (!PetscDualSpaceRegisterAllCalled) {ierr = PetscDualSpaceRegisterAll();CHKERRQ(ierr);}
1309   ierr = PetscFunctionListFind(PetscDualSpaceList, name, &r);CHKERRQ(ierr);
1310   if (!r) SETERRQ1(PetscObjectComm((PetscObject) sp), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscDualSpace type: %s", name);
1311 
1312   if (sp->ops->destroy) {
1313     ierr             = (*sp->ops->destroy)(sp);CHKERRQ(ierr);
1314     sp->ops->destroy = NULL;
1315   }
1316   ierr = (*r)(sp);CHKERRQ(ierr);
1317   ierr = PetscObjectChangeTypeName((PetscObject) sp, name);CHKERRQ(ierr);
1318   PetscFunctionReturn(0);
1319 }
1320 
1321 #undef __FUNCT__
1322 #define __FUNCT__ "PetscDualSpaceGetType"
1323 /*@C
1324   PetscDualSpaceGetType - Gets the PetscDualSpace type name (as a string) from the object.
1325 
1326   Not Collective
1327 
1328   Input Parameter:
1329 . dm  - The PetscDualSpace
1330 
1331   Output Parameter:
1332 . name - The PetscDualSpace type name
1333 
1334   Level: intermediate
1335 
1336 .keywords: PetscDualSpace, get, type, name
1337 .seealso: PetscDualSpaceSetType(), PetscDualSpaceCreate()
1338 @*/
1339 PetscErrorCode PetscDualSpaceGetType(PetscDualSpace sp, PetscDualSpaceType *name)
1340 {
1341   PetscErrorCode ierr;
1342 
1343   PetscFunctionBegin;
1344   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1345   PetscValidCharPointer(name, 2);
1346   if (!PetscDualSpaceRegisterAllCalled) {
1347     ierr = PetscDualSpaceRegisterAll();CHKERRQ(ierr);
1348   }
1349   *name = ((PetscObject) sp)->type_name;
1350   PetscFunctionReturn(0);
1351 }
1352 
1353 #undef __FUNCT__
1354 #define __FUNCT__ "PetscDualSpaceView"
1355 /*@C
1356   PetscDualSpaceView - Views a PetscDualSpace
1357 
1358   Collective on PetscDualSpace
1359 
1360   Input Parameter:
1361 + sp - the PetscDualSpace object to view
1362 - v  - the viewer
1363 
1364   Level: developer
1365 
1366 .seealso PetscDualSpaceDestroy()
1367 @*/
1368 PetscErrorCode PetscDualSpaceView(PetscDualSpace sp, PetscViewer v)
1369 {
1370   PetscErrorCode ierr;
1371 
1372   PetscFunctionBegin;
1373   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1374   if (!v) {
1375     ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject) sp), &v);CHKERRQ(ierr);
1376   }
1377   if (sp->ops->view) {
1378     ierr = (*sp->ops->view)(sp, v);CHKERRQ(ierr);
1379   }
1380   PetscFunctionReturn(0);
1381 }
1382 
1383 #undef __FUNCT__
1384 #define __FUNCT__ "PetscDualSpaceViewFromOptions"
1385 /*
1386   PetscDualSpaceViewFromOptions - Processes command line options to determine if/how a PetscDualSpace is to be viewed.
1387 
1388   Collective on PetscDualSpace
1389 
1390   Input Parameters:
1391 + sp   - the PetscDualSpace
1392 . prefix - prefix to use for viewing, or NULL to use prefix of 'rnd'
1393 - optionname - option to activate viewing
1394 
1395   Level: intermediate
1396 
1397 .keywords: PetscDualSpace, view, options, database
1398 .seealso: VecViewFromOptions(), MatViewFromOptions()
1399 */
1400 PetscErrorCode PetscDualSpaceViewFromOptions(PetscDualSpace sp, const char prefix[], const char optionname[])
1401 {
1402   PetscViewer       viewer;
1403   PetscViewerFormat format;
1404   PetscBool         flg;
1405   PetscErrorCode    ierr;
1406 
1407   PetscFunctionBegin;
1408   if (prefix) {
1409     ierr = PetscOptionsGetViewer(PetscObjectComm((PetscObject) sp), prefix, optionname, &viewer, &format, &flg);CHKERRQ(ierr);
1410   } else {
1411     ierr = PetscOptionsGetViewer(PetscObjectComm((PetscObject) sp), ((PetscObject) sp)->prefix, optionname, &viewer, &format, &flg);CHKERRQ(ierr);
1412   }
1413   if (flg) {
1414     ierr = PetscViewerPushFormat(viewer, format);CHKERRQ(ierr);
1415     ierr = PetscDualSpaceView(sp, viewer);CHKERRQ(ierr);
1416     ierr = PetscViewerPopFormat(viewer);CHKERRQ(ierr);
1417     ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
1418   }
1419   PetscFunctionReturn(0);
1420 }
1421 
1422 #undef __FUNCT__
1423 #define __FUNCT__ "PetscDualSpaceSetFromOptions"
1424 /*@
1425   PetscDualSpaceSetFromOptions - sets parameters in a PetscDualSpace from the options database
1426 
1427   Collective on PetscDualSpace
1428 
1429   Input Parameter:
1430 . sp - the PetscDualSpace object to set options for
1431 
1432   Options Database:
1433 . -petscspace_order the approximation order of the space
1434 
1435   Level: developer
1436 
1437 .seealso PetscDualSpaceView()
1438 @*/
1439 PetscErrorCode PetscDualSpaceSetFromOptions(PetscDualSpace sp)
1440 {
1441   const char    *defaultType;
1442   char           typename[256];
1443   PetscBool      flg;
1444   PetscErrorCode ierr;
1445 
1446   PetscFunctionBegin;
1447   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1448   if (!((PetscObject) sp)->type_name) {
1449     defaultType = PETSCDUALSPACELAGRANGE;
1450   } else {
1451     defaultType = ((PetscObject) sp)->type_name;
1452   }
1453   if (!PetscSpaceRegisterAllCalled) {ierr = PetscSpaceRegisterAll();CHKERRQ(ierr);}
1454 
1455   ierr = PetscObjectOptionsBegin((PetscObject) sp);CHKERRQ(ierr);
1456   ierr = PetscOptionsList("-petscdualspace_type", "Dual space", "PetscDualSpaceSetType", PetscDualSpaceList, defaultType, typename, 256, &flg);CHKERRQ(ierr);
1457   if (flg) {
1458     ierr = PetscDualSpaceSetType(sp, typename);CHKERRQ(ierr);
1459   } else if (!((PetscObject) sp)->type_name) {
1460     ierr = PetscDualSpaceSetType(sp, defaultType);CHKERRQ(ierr);
1461   }
1462   ierr = PetscOptionsInt("-petscdualspace_order", "The approximation order", "PetscDualSpaceSetOrder", sp->order, &sp->order, NULL);CHKERRQ(ierr);
1463   if (sp->ops->setfromoptions) {
1464     ierr = (*sp->ops->setfromoptions)(sp);CHKERRQ(ierr);
1465   }
1466   /* process any options handlers added with PetscObjectAddOptionsHandler() */
1467   ierr = PetscObjectProcessOptionsHandlers((PetscObject) sp);CHKERRQ(ierr);
1468   ierr = PetscOptionsEnd();CHKERRQ(ierr);
1469   ierr = PetscDualSpaceViewFromOptions(sp, NULL, "-petscdualspace_view");CHKERRQ(ierr);
1470   PetscFunctionReturn(0);
1471 }
1472 
1473 #undef __FUNCT__
1474 #define __FUNCT__ "PetscDualSpaceSetUp"
1475 /*@C
1476   PetscDualSpaceSetUp - Construct a basis for the PetscDualSpace
1477 
1478   Collective on PetscDualSpace
1479 
1480   Input Parameter:
1481 . sp - the PetscDualSpace object to setup
1482 
1483   Level: developer
1484 
1485 .seealso PetscDualSpaceView(), PetscDualSpaceDestroy()
1486 @*/
1487 PetscErrorCode PetscDualSpaceSetUp(PetscDualSpace sp)
1488 {
1489   PetscErrorCode ierr;
1490 
1491   PetscFunctionBegin;
1492   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1493   if (sp->ops->setup) {ierr = (*sp->ops->setup)(sp);CHKERRQ(ierr);}
1494   PetscFunctionReturn(0);
1495 }
1496 
1497 #undef __FUNCT__
1498 #define __FUNCT__ "PetscDualSpaceDestroy"
1499 /*@
1500   PetscDualSpaceDestroy - Destroys a PetscDualSpace object
1501 
1502   Collective on PetscDualSpace
1503 
1504   Input Parameter:
1505 . sp - the PetscDualSpace object to destroy
1506 
1507   Level: developer
1508 
1509 .seealso PetscDualSpaceView()
1510 @*/
1511 PetscErrorCode PetscDualSpaceDestroy(PetscDualSpace *sp)
1512 {
1513   PetscInt       dim, f;
1514   PetscErrorCode ierr;
1515 
1516   PetscFunctionBegin;
1517   if (!*sp) PetscFunctionReturn(0);
1518   PetscValidHeaderSpecific((*sp), PETSCDUALSPACE_CLASSID, 1);
1519 
1520   if (--((PetscObject)(*sp))->refct > 0) {*sp = 0; PetscFunctionReturn(0);}
1521   ((PetscObject) (*sp))->refct = 0;
1522   /* if memory was published with AMS then destroy it */
1523   ierr = PetscObjectAMSViewOff((PetscObject) *sp);CHKERRQ(ierr);
1524 
1525   ierr = DMDestroy(&(*sp)->dm);CHKERRQ(ierr);
1526   ierr = PetscDualSpaceGetDimension(*sp, &dim);CHKERRQ(ierr);
1527   for (f = 0; f < dim; ++f) {
1528     /* ierr = PetscQuadratureDestroy((*sp)->functional[f]);CHKERRQ(ierr); */
1529   }
1530   ierr = PetscFree((*sp)->functional);CHKERRQ(ierr);
1531 
1532   ierr = (*(*sp)->ops->destroy)(*sp);CHKERRQ(ierr);
1533   ierr = PetscHeaderDestroy(sp);CHKERRQ(ierr);
1534   PetscFunctionReturn(0);
1535 }
1536 
1537 #undef __FUNCT__
1538 #define __FUNCT__ "PetscDualSpaceCreate"
1539 /*@
1540   PetscDualSpaceCreate - Creates an empty PetscDualSpace object. The type can then be set with PetscDualSpaceSetType().
1541 
1542   Collective on MPI_Comm
1543 
1544   Input Parameter:
1545 . comm - The communicator for the PetscDualSpace object
1546 
1547   Output Parameter:
1548 . sp - The PetscDualSpace object
1549 
1550   Level: beginner
1551 
1552 .seealso: PetscDualSpaceSetType(), PETSCDUALSPACELAGRANGE
1553 @*/
1554 PetscErrorCode PetscDualSpaceCreate(MPI_Comm comm, PetscDualSpace *sp)
1555 {
1556   PetscDualSpace s;
1557   PetscErrorCode ierr;
1558 
1559   PetscFunctionBegin;
1560   PetscValidPointer(sp, 2);
1561   *sp = NULL;
1562 #if !defined(PETSC_USE_DYNAMIC_LIBRARIES)
1563   ierr = PetscFEInitializePackage();CHKERRQ(ierr);
1564 #endif
1565 
1566   ierr = PetscHeaderCreate(s, _p_PetscDualSpace, struct _PetscDualSpaceOps, PETSCDUALSPACE_CLASSID, "PetscDualSpace", "Dual Space", "PetscDualSpace", comm, PetscDualSpaceDestroy, PetscDualSpaceView);CHKERRQ(ierr);
1567   ierr = PetscMemzero(s->ops, sizeof(struct _PetscDualSpaceOps));CHKERRQ(ierr);
1568 
1569   s->order = 0;
1570 
1571   *sp = s;
1572   PetscFunctionReturn(0);
1573 }
1574 
1575 #undef __FUNCT__
1576 #define __FUNCT__ "PetscDualSpaceGetDM"
1577 PetscErrorCode PetscDualSpaceGetDM(PetscDualSpace sp, DM *dm)
1578 {
1579   PetscFunctionBegin;
1580   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1581   PetscValidPointer(dm, 2);
1582   *dm = sp->dm;
1583   PetscFunctionReturn(0);
1584 }
1585 
1586 #undef __FUNCT__
1587 #define __FUNCT__ "PetscDualSpaceSetDM"
1588 PetscErrorCode PetscDualSpaceSetDM(PetscDualSpace sp, DM dm)
1589 {
1590   PetscErrorCode ierr;
1591 
1592   PetscFunctionBegin;
1593   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1594   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
1595   ierr = DMDestroy(&sp->dm);CHKERRQ(ierr);
1596   ierr = PetscObjectReference((PetscObject) dm);CHKERRQ(ierr);
1597   sp->dm = dm;
1598   PetscFunctionReturn(0);
1599 }
1600 
1601 #undef __FUNCT__
1602 #define __FUNCT__ "PetscDualSpaceGetOrder"
1603 PetscErrorCode PetscDualSpaceGetOrder(PetscDualSpace sp, PetscInt *order)
1604 {
1605   PetscFunctionBegin;
1606   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1607   PetscValidPointer(order, 2);
1608   *order = sp->order;
1609   PetscFunctionReturn(0);
1610 }
1611 
1612 #undef __FUNCT__
1613 #define __FUNCT__ "PetscDualSpaceSetOrder"
1614 PetscErrorCode PetscDualSpaceSetOrder(PetscDualSpace sp, PetscInt order)
1615 {
1616   PetscFunctionBegin;
1617   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1618   sp->order = order;
1619   PetscFunctionReturn(0);
1620 }
1621 
1622 #undef __FUNCT__
1623 #define __FUNCT__ "PetscDualSpaceGetFunctional"
1624 PetscErrorCode PetscDualSpaceGetFunctional(PetscDualSpace sp, PetscInt i, PetscQuadrature *functional)
1625 {
1626   PetscInt       dim;
1627   PetscErrorCode ierr;
1628 
1629   PetscFunctionBegin;
1630   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1631   PetscValidPointer(functional, 3);
1632   ierr = PetscDualSpaceGetDimension(sp, &dim);CHKERRQ(ierr);
1633   if ((i < 0) || (i >= dim)) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Functional index %d must be in [0, %d)", i, dim);
1634   *functional = sp->functional[i];
1635   PetscFunctionReturn(0);
1636 }
1637 
1638 #undef __FUNCT__
1639 #define __FUNCT__ "PetscDualSpaceGetDimension"
1640 /* Dimension of the space, i.e. number of basis vectors */
1641 PetscErrorCode PetscDualSpaceGetDimension(PetscDualSpace sp, PetscInt *dim)
1642 {
1643   PetscErrorCode ierr;
1644 
1645   PetscFunctionBegin;
1646   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1647   PetscValidPointer(dim, 2);
1648   *dim = 0;
1649   if (sp->ops->getdimension) {ierr = (*sp->ops->getdimension)(sp, dim);CHKERRQ(ierr);}
1650   PetscFunctionReturn(0);
1651 }
1652 
1653 #undef __FUNCT__
1654 #define __FUNCT__ "PetscDualSpaceSetUp_Lagrange"
1655 PetscErrorCode PetscDualSpaceSetUp_Lagrange(PetscDualSpace sp)
1656 {
1657   DM             dm    = sp->dm;
1658   PetscInt       order = sp->order;
1659   PetscSection   csection;
1660   Vec            coordinates;
1661   PetscReal     *qpoints, *qweights;
1662   PetscInt       depth, dim, pdim, *pStart, *pEnd, coneSize, d, n, f = 0;
1663   PetscErrorCode ierr;
1664 
1665   PetscFunctionBegin;
1666   ierr = PetscDualSpaceGetDimension(sp, &pdim);CHKERRQ(ierr);
1667   ierr = PetscMalloc(pdim * sizeof(PetscQuadrature), &sp->functional);CHKERRQ(ierr);
1668   /* Classify element type */
1669   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
1670   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1671   ierr = PetscMalloc2(depth+1,PetscInt,&pStart,depth+1,PetscInt,&pEnd);CHKERRQ(ierr);
1672   for (d = 0; d < depth; ++d) {
1673     ierr = DMPlexGetDepthStratum(dm, d, &pStart[d], &pEnd[d]);CHKERRQ(ierr);
1674   }
1675   ierr = DMPlexGetConeSize(dm, pStart[depth], &coneSize);CHKERRQ(ierr);
1676   ierr = DMPlexGetCoordinateSection(dm, &csection);CHKERRQ(ierr);
1677   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
1678   if (coneSize == dim+1) {
1679     PetscInt *closure = NULL, closureSize, c;
1680 
1681     /* Simplex */
1682     ierr = DMPlexGetTransitiveClosure(dm, pStart[depth], PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
1683     for (c = 0; c < closureSize*2; c += 2) {
1684       const PetscInt p = closure[c];
1685 
1686       if ((p >= pStart[0]) && (p < pEnd[0])) {
1687         /* Vertices */
1688         const PetscScalar *coords;
1689         PetscInt           dof, off, d;
1690 
1691         if (order < 1) continue;
1692         sp->functional[f].numQuadPoints = 1;
1693         ierr = PetscMalloc(sp->functional[f].numQuadPoints*dim * sizeof(PetscReal), &qpoints);CHKERRQ(ierr);
1694         ierr = PetscMalloc(sp->functional[f].numQuadPoints     * sizeof(PetscReal), &qweights);CHKERRQ(ierr);
1695         ierr = VecGetArrayRead(coordinates, &coords);CHKERRQ(ierr);
1696         ierr = PetscSectionGetDof(csection, p, &dof);CHKERRQ(ierr);
1697         ierr = PetscSectionGetOffset(csection, p, &off);CHKERRQ(ierr);
1698         if (dof != dim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of coordinates %d does not match spatial dimension %d", dof, dim);
1699         for (d = 0; d < dof; ++d) {qpoints[d] = coords[off+d];}
1700         qweights[0] = 1.0;
1701         sp->functional[f].quadPoints  = qpoints;
1702         sp->functional[f].quadWeights = qweights;
1703         ++f;
1704         ierr = VecRestoreArrayRead(coordinates, &coords);CHKERRQ(ierr);
1705       } else if ((p >= pStart[1]) && (p < pEnd[1])) {
1706         /* Edges */
1707         PetscScalar *coords;
1708         PetscInt     k;
1709 
1710         if (order < 2) continue;
1711         coords = NULL;
1712         ierr = DMPlexVecGetClosure(dm, csection, coordinates, p, &n, &coords);CHKERRQ(ierr);
1713         if (n != dim*2) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %d has %d coordinate values instead of %d", p, n, dim*2);
1714         for (k = 1; k < order; ++k) {
1715           sp->functional[f].numQuadPoints = 1;
1716           ierr = PetscMalloc(sp->functional[f].numQuadPoints*dim * sizeof(PetscReal), &qpoints);CHKERRQ(ierr);
1717           ierr = PetscMalloc(sp->functional[f].numQuadPoints     * sizeof(PetscReal), &qweights);CHKERRQ(ierr);
1718           for (d = 0; d < dim; ++d) {qpoints[d] = k*(coords[1*dim+d] - coords[0*dim+d])/order + coords[0*dim+d];}
1719           qweights[0] = 1.0;
1720           sp->functional[f].quadPoints  = qpoints;
1721           sp->functional[f].quadWeights = qweights;
1722           ++f;
1723         }
1724         ierr = DMPlexVecRestoreClosure(dm, csection, coordinates, p, &n, &coords);CHKERRQ(ierr);
1725       } else if ((p >= pStart[depth-1]) && (p < pEnd[depth-1])) {
1726         /* Faces */
1727 
1728         if (order < 3) continue;
1729         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Too lazy to implement faces");
1730       } else if ((p >= pStart[depth]) && (p < pEnd[depth])) {
1731         /* Cells */
1732 
1733         if ((order > 0) && (order < 3)) continue;
1734         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Too lazy to implement cells");
1735       }
1736     }
1737     ierr = DMPlexRestoreTransitiveClosure(dm, pStart[depth], PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
1738   } else SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Cannot handle cells with cone size %d", coneSize);
1739   ierr = PetscFree2(pStart,pEnd);CHKERRQ(ierr);
1740   if (f != pdim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of dual basis vector %d not equal to dimension %d", f, pdim);
1741   PetscFunctionReturn(0);
1742 }
1743 
1744 #undef __FUNCT__
1745 #define __FUNCT__ "PetscDualSpaceGetDimension_Lagrange"
1746 PetscErrorCode PetscDualSpaceGetDimension_Lagrange(PetscDualSpace sp, PetscInt *dim)
1747 {
1748   PetscInt            deg = sp->order;
1749   PetscReal           D   = 1.0;
1750   PetscInt            n, i;
1751   PetscErrorCode      ierr;
1752 
1753   PetscFunctionBegin;
1754   /* TODO: Assumes simplices */
1755   ierr = DMPlexGetDimension(sp->dm, &n);CHKERRQ(ierr);
1756   for (i = 1; i <= n; ++i) {
1757     D *= ((PetscReal) (deg+i))/i;
1758   }
1759   *dim = (PetscInt) (D + 0.5);
1760   PetscFunctionReturn(0);
1761 }
1762 
1763 #undef __FUNCT__
1764 #define __FUNCT__ "PetscDualSpaceInitialize_Lagrange"
1765 PetscErrorCode PetscDualSpaceInitialize_Lagrange(PetscDualSpace sp)
1766 {
1767   PetscFunctionBegin;
1768   sp->ops->setfromoptions = NULL;
1769   sp->ops->setup          = PetscDualSpaceSetUp_Lagrange;
1770   sp->ops->view           = NULL;
1771   sp->ops->destroy        = NULL;
1772   sp->ops->getdimension   = PetscDualSpaceGetDimension_Lagrange;
1773   PetscFunctionReturn(0);
1774 }
1775 
1776 /*MC
1777   PETSCDUALSPACELAGRANGE = "lagrange" - A PetscDualSpace object that encapsulates a dual space of pointwise evaluation functionals
1778 
1779   Level: intermediate
1780 
1781 .seealso: PetscDualSpaceType, PetscDualSpaceCreate(), PetscDualSpaceSetType()
1782 M*/
1783 
1784 #undef __FUNCT__
1785 #define __FUNCT__ "PetscDualSpaceCreate_Lagrange"
1786 PETSC_EXTERN PetscErrorCode PetscDualSpaceCreate_Lagrange(PetscDualSpace sp)
1787 {
1788   PetscDualSpace_Lag *lag;
1789   PetscErrorCode      ierr;
1790 
1791   PetscFunctionBegin;
1792   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 1);
1793   ierr     = PetscNewLog(sp, PetscDualSpace_Lag, &lag);CHKERRQ(ierr);
1794   sp->data = lag;
1795 
1796   /* lag->n = 0; */
1797 
1798   ierr = PetscDualSpaceInitialize_Lagrange(sp);CHKERRQ(ierr);
1799   PetscFunctionReturn(0);
1800 }
1801 
1802 
1803 PetscInt PETSCFE_CLASSID = 0;
1804 
1805 #undef __FUNCT__
1806 #define __FUNCT__ "PetscFEView"
1807 /*@C
1808   PetscFEView - Views a PetscFE
1809 
1810   Collective on PetscFE
1811 
1812   Input Parameter:
1813 + sp - the PetscFE object to view
1814 - v  - the viewer
1815 
1816   Level: developer
1817 
1818 .seealso PetscFEDestroy()
1819 @*/
1820 PetscErrorCode PetscFEView(PetscFE fem, PetscViewer v)
1821 {
1822   PetscErrorCode ierr;
1823 
1824   PetscFunctionBegin;
1825   PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1);
1826   if (!v) {
1827     ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject) fem), &v);CHKERRQ(ierr);
1828   }
1829   if (fem->ops->view) {
1830     ierr = (*fem->ops->view)(fem, v);CHKERRQ(ierr);
1831   }
1832   PetscFunctionReturn(0);
1833 }
1834 
1835 #undef __FUNCT__
1836 #define __FUNCT__ "PetscFEDestroy"
1837 /*@
1838   PetscFEDestroy - Destroys a PetscFE object
1839 
1840   Collective on PetscFE
1841 
1842   Input Parameter:
1843 . fem - the PetscFE object to destroy
1844 
1845   Level: developer
1846 
1847 .seealso PetscFEView()
1848 @*/
1849 PetscErrorCode PetscFEDestroy(PetscFE *fem)
1850 {
1851   PetscErrorCode ierr;
1852 
1853   PetscFunctionBegin;
1854   if (!*fem) PetscFunctionReturn(0);
1855   PetscValidHeaderSpecific((*fem), PETSCFE_CLASSID, 1);
1856 
1857   if (--((PetscObject)(*fem))->refct > 0) {*fem = 0; PetscFunctionReturn(0);}
1858   ((PetscObject) (*fem))->refct = 0;
1859   /* if memory was published with AMS then destroy it */
1860   ierr = PetscObjectAMSViewOff((PetscObject) *fem);CHKERRQ(ierr);
1861 
1862   ierr = (*(*fem)->ops->destroy)(*fem);CHKERRQ(ierr);
1863   ierr = PetscHeaderDestroy(fem);CHKERRQ(ierr);
1864   PetscFunctionReturn(0);
1865 }
1866 
1867 #undef __FUNCT__
1868 #define __FUNCT__ "PetscFECreate"
1869 /*@
1870   PetscFECreate - Creates an empty PetscFE object. The type can then be set with PetscFESetType().
1871 
1872   Collective on MPI_Comm
1873 
1874   Input Parameter:
1875 . comm - The communicator for the PetscFE object
1876 
1877   Output Parameter:
1878 . fem - The PetscFE object
1879 
1880   Level: beginner
1881 
1882 .seealso: PetscFESetType(), PETSCFEGALERKIN
1883 @*/
1884 PetscErrorCode PetscFECreate(MPI_Comm comm, PetscFE *fem)
1885 {
1886   PetscFE        f;
1887   PetscErrorCode ierr;
1888 
1889   PetscFunctionBegin;
1890   PetscValidPointer(fem, 2);
1891   *fem = NULL;
1892 #if !defined(PETSC_USE_DYNAMIC_LIBRARIES)
1893   ierr = PetscFEInitializePackage();CHKERRQ(ierr);
1894 #endif
1895 
1896   ierr = PetscHeaderCreate(f, _p_PetscFE, struct _PetscFEOps, PETSCFE_CLASSID, "PetscFE", "Finite Element", "PetscFE", comm, PetscFEDestroy, PetscFEView);CHKERRQ(ierr);
1897   ierr = PetscMemzero(f->ops, sizeof(struct _PetscFEOps));CHKERRQ(ierr);
1898 
1899   f->basisSpace    = NULL;
1900   f->dualSpace     = NULL;
1901   f->numComponents = 1;
1902 
1903   *fem = f;
1904   PetscFunctionReturn(0);
1905 }
1906 
1907 #undef __FUNCT__
1908 #define __FUNCT__ "PetscFEGetDimension"
1909 PetscErrorCode PetscFEGetDimension(PetscFE fem, PetscInt *dim)
1910 {
1911   PetscErrorCode ierr;
1912 
1913   PetscFunctionBegin;
1914   PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1);
1915   PetscValidPointer(dim, 2);
1916   ierr = PetscSpaceGetDimension(fem->basisSpace, dim);CHKERRQ(ierr);
1917   PetscFunctionReturn(0);
1918 }
1919 
1920 #undef __FUNCT__
1921 #define __FUNCT__ "PetscFESetNumComponents"
1922 PetscErrorCode PetscFESetNumComponents(PetscFE fem, PetscInt comp)
1923 {
1924   PetscFunctionBegin;
1925   PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1);
1926   fem->numComponents = comp;
1927   PetscFunctionReturn(0);
1928 }
1929 
1930 #undef __FUNCT__
1931 #define __FUNCT__ "PetscFEGetNumComponents"
1932 PetscErrorCode PetscFEGetNumComponents(PetscFE fem, PetscInt *comp)
1933 {
1934   PetscFunctionBegin;
1935   PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1);
1936   PetscValidPointer(comp, 2);
1937   *comp = fem->numComponents;
1938   PetscFunctionReturn(0);
1939 }
1940 
1941 #undef __FUNCT__
1942 #define __FUNCT__ "PetscFEGetBasisSpace"
1943 PetscErrorCode PetscFEGetBasisSpace(PetscFE fem, PetscSpace *sp)
1944 {
1945   PetscFunctionBegin;
1946   PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1);
1947   PetscValidPointer(sp, 2);
1948   *sp = fem->basisSpace;
1949   PetscFunctionReturn(0);
1950 }
1951 
1952 #undef __FUNCT__
1953 #define __FUNCT__ "PetscFESetBasisSpace"
1954 PetscErrorCode PetscFESetBasisSpace(PetscFE fem, PetscSpace sp)
1955 {
1956   PetscFunctionBegin;
1957   PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1);
1958   PetscValidHeaderSpecific(sp, PETSCSPACE_CLASSID, 2);
1959   fem->basisSpace = sp;
1960   PetscFunctionReturn(0);
1961 }
1962 
1963 #undef __FUNCT__
1964 #define __FUNCT__ "PetscFEGetDualSpace"
1965 PetscErrorCode PetscFEGetDualSpace(PetscFE fem, PetscDualSpace *sp)
1966 {
1967   PetscFunctionBegin;
1968   PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1);
1969   PetscValidPointer(sp, 2);
1970   *sp = fem->dualSpace;
1971   PetscFunctionReturn(0);
1972 }
1973 
1974 #undef __FUNCT__
1975 #define __FUNCT__ "PetscFESetDualSpace"
1976 PetscErrorCode PetscFESetDualSpace(PetscFE fem, PetscDualSpace sp)
1977 {
1978   PetscFunctionBegin;
1979   PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1);
1980   PetscValidHeaderSpecific(sp, PETSCDUALSPACE_CLASSID, 2);
1981   fem->dualSpace = sp;
1982   PetscFunctionReturn(0);
1983 }
1984 
1985 #undef __FUNCT__
1986 #define __FUNCT__ "PetscFEGetTabulation"
1987 PetscErrorCode PetscFEGetTabulation(PetscFE fem, PetscInt npoints, const PetscReal points[], PetscReal **B, PetscReal **D, PetscReal **H)
1988 {
1989   DM             dm;
1990   PetscReal     *tmpB, *invV;
1991   PetscInt       pdim; /* Dimension of FE space P */
1992   PetscInt       dim;  /* Spatial dimension */
1993   PetscInt       comp; /* Field components */
1994   PetscInt       p, j, k;
1995   PetscErrorCode ierr;
1996 
1997   PetscFunctionBegin;
1998   PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1);
1999   PetscValidPointer(points, 3);
2000   if (B) PetscValidPointer(B, 4);
2001   if (D) PetscValidPointer(D, 5);
2002   if (H) PetscValidPointer(H, 6);
2003   ierr = PetscDualSpaceGetDM(fem->dualSpace, &dm);CHKERRQ(ierr);
2004 
2005   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
2006   ierr = PetscSpaceGetDimension(fem->basisSpace, &pdim);CHKERRQ(ierr);
2007   ierr = PetscFEGetNumComponents(fem, &comp);CHKERRQ(ierr);
2008   /* if (nvalues%dim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "The number of coordinate values %d must be divisible by the spatial dimension %d", nvalues, dim); */
2009 
2010   if (B) {
2011     ierr = DMGetWorkArray(dm, npoints*pdim*comp, PETSC_REAL, B);CHKERRQ(ierr);
2012     ierr = DMGetWorkArray(dm, npoints*pdim, PETSC_REAL, &tmpB);CHKERRQ(ierr);
2013   }
2014   if (D) {ierr = DMGetWorkArray(dm, npoints*pdim*dim, PETSC_REAL, D);CHKERRQ(ierr);}
2015   if (H) {ierr = DMGetWorkArray(dm, npoints*pdim*dim*dim, PETSC_REAL, H);CHKERRQ(ierr);}
2016   ierr = PetscSpaceEvaluate(fem->basisSpace, npoints, points, B ? tmpB : NULL, D ? *D : NULL, H ? *H : NULL);CHKERRQ(ierr);
2017 
2018   ierr = DMGetWorkArray(dm, pdim*pdim, PETSC_REAL, &invV);CHKERRQ(ierr);
2019   for (j = 0; j < pdim; ++j) {
2020     PetscReal      *Bf;
2021     PetscQuadrature f;
2022     PetscInt        q;
2023 
2024     ierr = PetscDualSpaceGetFunctional(fem->dualSpace, j, &f);
2025     ierr = DMGetWorkArray(dm, f.numQuadPoints*pdim, PETSC_REAL, &Bf);CHKERRQ(ierr);
2026     ierr = PetscSpaceEvaluate(fem->basisSpace, f.numQuadPoints, f.quadPoints, Bf, NULL, NULL);CHKERRQ(ierr);
2027     for (k = 0; k < pdim; ++k) {
2028       /* n_j \cdot \phi_k */
2029       invV[j*pdim+k] = 0.0;
2030       for (q = 0; q < f.numQuadPoints; ++q) {
2031         invV[j*pdim+k] += Bf[q*pdim+k]*f.quadWeights[q];
2032       }
2033     }
2034     ierr = DMRestoreWorkArray(dm, f.numQuadPoints*pdim, PETSC_REAL, &Bf);CHKERRQ(ierr);
2035   }
2036   {
2037     PetscReal    *work;
2038     PetscBLASInt *pivots;
2039     PetscBLASInt  n = pdim, info;
2040 
2041     ierr = DMGetWorkArray(dm, pdim, PETSC_INT, &pivots);CHKERRQ(ierr);
2042     ierr = DMGetWorkArray(dm, pdim, PETSC_REAL, &work);CHKERRQ(ierr);
2043     PetscStackCallBLAS("LAPACKgetrf", LAPACKgetrf_(&n, &n, invV, &n, pivots, &info));
2044     PetscStackCallBLAS("LAPACKgetri", LAPACKgetri_(&n, invV, &n, pivots, work, &n, &info));
2045     ierr = DMRestoreWorkArray(dm, pdim, PETSC_INT, &pivots);CHKERRQ(ierr);
2046     ierr = DMRestoreWorkArray(dm, pdim, PETSC_REAL, &work);CHKERRQ(ierr);
2047   }
2048   for (p = 0; p < npoints; ++p) {
2049     if (B) {
2050       /* Multiply by V^{-1} (pdim x pdim) */
2051       for (j = 0; j < pdim; ++j) {
2052         const PetscInt i = (p*pdim + j)*comp;
2053         PetscInt       c;
2054 
2055         (*B)[i] = 0.0;
2056         for (k = 0; k < pdim; ++k) {
2057           (*B)[i] += invV[k*pdim+j] * tmpB[p*pdim + k];
2058         }
2059         for (c = 1; c < comp; ++c) {
2060           (*B)[i+c] = (*B)[i];
2061         }
2062       }
2063     }
2064   }
2065   ierr = DMRestoreWorkArray(dm, pdim*pdim, PETSC_REAL, &invV);CHKERRQ(ierr);
2066   if (B) {
2067     ierr = DMRestoreWorkArray(dm, npoints*pdim, PETSC_REAL, &tmpB);CHKERRQ(ierr);
2068   }
2069   PetscFunctionReturn(0);
2070 }
2071 
2072 #undef __FUNCT__
2073 #define __FUNCT__ "PetscFERestoreTabulation"
2074 PetscErrorCode PetscFERestoreTabulation(PetscFE fem, PetscInt npoints, const PetscReal points[], PetscReal **B, PetscReal **D, PetscReal **D2)
2075 {
2076   DM             dm;
2077   PetscErrorCode ierr;
2078 
2079   PetscFunctionBegin;
2080   PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1);
2081   ierr = PetscDualSpaceGetDM(fem->dualSpace, &dm);CHKERRQ(ierr);
2082   if (B)  {ierr = DMRestoreWorkArray(dm, 0, PETSC_REAL, B);CHKERRQ(ierr);}
2083   if (D)  {ierr = DMRestoreWorkArray(dm, 0, PETSC_REAL, D);CHKERRQ(ierr);}
2084   if (D2) {ierr = DMRestoreWorkArray(dm, 0, PETSC_REAL, D2);CHKERRQ(ierr);}
2085   PetscFunctionReturn(0);
2086 }
2087