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