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