1 /* Discretization tools */ 2 3 #include <petscdt.h> /*I "petscdt.h" I*/ 4 #include <petscblaslapack.h> 5 #include <petsc/private/petscimpl.h> 6 #include <petsc/private/dtimpl.h> 7 #include <petscviewer.h> 8 #include <petscdmplex.h> 9 #include <petscdmshell.h> 10 11 #if defined(PETSC_HAVE_MPFR) 12 #include <mpfr.h> 13 #endif 14 15 static PetscBool GaussCite = PETSC_FALSE; 16 const char GaussCitation[] = "@article{GolubWelsch1969,\n" 17 " author = {Golub and Welsch},\n" 18 " title = {Calculation of Quadrature Rules},\n" 19 " journal = {Math. Comp.},\n" 20 " volume = {23},\n" 21 " number = {106},\n" 22 " pages = {221--230},\n" 23 " year = {1969}\n}\n"; 24 25 /*@ 26 PetscQuadratureCreate - Create a PetscQuadrature object 27 28 Collective on MPI_Comm 29 30 Input Parameter: 31 . comm - The communicator for the PetscQuadrature object 32 33 Output Parameter: 34 . q - The PetscQuadrature object 35 36 Level: beginner 37 38 .seealso: PetscQuadratureDestroy(), PetscQuadratureGetData() 39 @*/ 40 PetscErrorCode PetscQuadratureCreate(MPI_Comm comm, PetscQuadrature *q) 41 { 42 PetscErrorCode ierr; 43 44 PetscFunctionBegin; 45 PetscValidPointer(q, 2); 46 ierr = PetscSysInitializePackage();CHKERRQ(ierr); 47 ierr = PetscHeaderCreate(*q,PETSC_OBJECT_CLASSID,"PetscQuadrature","Quadrature","DT",comm,PetscQuadratureDestroy,PetscQuadratureView);CHKERRQ(ierr); 48 (*q)->dim = -1; 49 (*q)->Nc = 1; 50 (*q)->order = -1; 51 (*q)->numPoints = 0; 52 (*q)->points = NULL; 53 (*q)->weights = NULL; 54 PetscFunctionReturn(0); 55 } 56 57 /*@ 58 PetscQuadratureDuplicate - Create a deep copy of the PetscQuadrature object 59 60 Collective on PetscQuadrature 61 62 Input Parameter: 63 . q - The PetscQuadrature object 64 65 Output Parameter: 66 . r - The new PetscQuadrature object 67 68 Level: beginner 69 70 .seealso: PetscQuadratureCreate(), PetscQuadratureDestroy(), PetscQuadratureGetData() 71 @*/ 72 PetscErrorCode PetscQuadratureDuplicate(PetscQuadrature q, PetscQuadrature *r) 73 { 74 PetscInt order, dim, Nc, Nq; 75 const PetscReal *points, *weights; 76 PetscReal *p, *w; 77 PetscErrorCode ierr; 78 79 PetscFunctionBegin; 80 PetscValidPointer(q, 2); 81 ierr = PetscQuadratureCreate(PetscObjectComm((PetscObject) q), r);CHKERRQ(ierr); 82 ierr = PetscQuadratureGetOrder(q, &order);CHKERRQ(ierr); 83 ierr = PetscQuadratureSetOrder(*r, order);CHKERRQ(ierr); 84 ierr = PetscQuadratureGetData(q, &dim, &Nc, &Nq, &points, &weights);CHKERRQ(ierr); 85 ierr = PetscMalloc1(Nq*dim, &p);CHKERRQ(ierr); 86 ierr = PetscMalloc1(Nq*Nc, &w);CHKERRQ(ierr); 87 ierr = PetscMemcpy(p, points, Nq*dim * sizeof(PetscReal));CHKERRQ(ierr); 88 ierr = PetscMemcpy(w, weights, Nc * Nq * sizeof(PetscReal));CHKERRQ(ierr); 89 ierr = PetscQuadratureSetData(*r, dim, Nc, Nq, p, w);CHKERRQ(ierr); 90 PetscFunctionReturn(0); 91 } 92 93 /*@ 94 PetscQuadratureDestroy - Destroys a PetscQuadrature object 95 96 Collective on PetscQuadrature 97 98 Input Parameter: 99 . q - The PetscQuadrature object 100 101 Level: beginner 102 103 .seealso: PetscQuadratureCreate(), PetscQuadratureGetData() 104 @*/ 105 PetscErrorCode PetscQuadratureDestroy(PetscQuadrature *q) 106 { 107 PetscErrorCode ierr; 108 109 PetscFunctionBegin; 110 if (!*q) PetscFunctionReturn(0); 111 PetscValidHeaderSpecific((*q),PETSC_OBJECT_CLASSID,1); 112 if (--((PetscObject)(*q))->refct > 0) { 113 *q = NULL; 114 PetscFunctionReturn(0); 115 } 116 ierr = PetscFree((*q)->points);CHKERRQ(ierr); 117 ierr = PetscFree((*q)->weights);CHKERRQ(ierr); 118 ierr = PetscHeaderDestroy(q);CHKERRQ(ierr); 119 PetscFunctionReturn(0); 120 } 121 122 /*@ 123 PetscQuadratureGetOrder - Return the order of the method 124 125 Not collective 126 127 Input Parameter: 128 . q - The PetscQuadrature object 129 130 Output Parameter: 131 . order - The order of the quadrature, i.e. the highest degree polynomial that is exactly integrated 132 133 Level: intermediate 134 135 .seealso: PetscQuadratureSetOrder(), PetscQuadratureGetData(), PetscQuadratureSetData() 136 @*/ 137 PetscErrorCode PetscQuadratureGetOrder(PetscQuadrature q, PetscInt *order) 138 { 139 PetscFunctionBegin; 140 PetscValidHeaderSpecific(q, PETSC_OBJECT_CLASSID, 1); 141 PetscValidPointer(order, 2); 142 *order = q->order; 143 PetscFunctionReturn(0); 144 } 145 146 /*@ 147 PetscQuadratureSetOrder - Return the order of the method 148 149 Not collective 150 151 Input Parameters: 152 + q - The PetscQuadrature object 153 - order - The order of the quadrature, i.e. the highest degree polynomial that is exactly integrated 154 155 Level: intermediate 156 157 .seealso: PetscQuadratureGetOrder(), PetscQuadratureGetData(), PetscQuadratureSetData() 158 @*/ 159 PetscErrorCode PetscQuadratureSetOrder(PetscQuadrature q, PetscInt order) 160 { 161 PetscFunctionBegin; 162 PetscValidHeaderSpecific(q, PETSC_OBJECT_CLASSID, 1); 163 q->order = order; 164 PetscFunctionReturn(0); 165 } 166 167 /*@ 168 PetscQuadratureGetNumComponents - Return the number of components for functions to be integrated 169 170 Not collective 171 172 Input Parameter: 173 . q - The PetscQuadrature object 174 175 Output Parameter: 176 . Nc - The number of components 177 178 Note: We are performing an integral int f(x) . w(x) dx, where both f and w (the weight) have Nc components. 179 180 Level: intermediate 181 182 .seealso: PetscQuadratureSetNumComponents(), PetscQuadratureGetData(), PetscQuadratureSetData() 183 @*/ 184 PetscErrorCode PetscQuadratureGetNumComponents(PetscQuadrature q, PetscInt *Nc) 185 { 186 PetscFunctionBegin; 187 PetscValidHeaderSpecific(q, PETSC_OBJECT_CLASSID, 1); 188 PetscValidPointer(Nc, 2); 189 *Nc = q->Nc; 190 PetscFunctionReturn(0); 191 } 192 193 /*@ 194 PetscQuadratureSetNumComponents - Return the number of components for functions to be integrated 195 196 Not collective 197 198 Input Parameters: 199 + q - The PetscQuadrature object 200 - Nc - The number of components 201 202 Note: We are performing an integral int f(x) . w(x) dx, where both f and w (the weight) have Nc components. 203 204 Level: intermediate 205 206 .seealso: PetscQuadratureGetNumComponents(), PetscQuadratureGetData(), PetscQuadratureSetData() 207 @*/ 208 PetscErrorCode PetscQuadratureSetNumComponents(PetscQuadrature q, PetscInt Nc) 209 { 210 PetscFunctionBegin; 211 PetscValidHeaderSpecific(q, PETSC_OBJECT_CLASSID, 1); 212 q->Nc = Nc; 213 PetscFunctionReturn(0); 214 } 215 216 /*@C 217 PetscQuadratureGetData - Returns the data defining the quadrature 218 219 Not collective 220 221 Input Parameter: 222 . q - The PetscQuadrature object 223 224 Output Parameters: 225 + dim - The spatial dimension 226 . Nc - The number of components 227 . npoints - The number of quadrature points 228 . points - The coordinates of each quadrature point 229 - weights - The weight of each quadrature point 230 231 Level: intermediate 232 233 Fortran Notes: 234 From Fortran you must call PetscQuadratureRestoreData() when you are done with the data 235 236 .seealso: PetscQuadratureCreate(), PetscQuadratureSetData() 237 @*/ 238 PetscErrorCode PetscQuadratureGetData(PetscQuadrature q, PetscInt *dim, PetscInt *Nc, PetscInt *npoints, const PetscReal *points[], const PetscReal *weights[]) 239 { 240 PetscFunctionBegin; 241 PetscValidHeaderSpecific(q, PETSC_OBJECT_CLASSID, 1); 242 if (dim) { 243 PetscValidPointer(dim, 2); 244 *dim = q->dim; 245 } 246 if (Nc) { 247 PetscValidPointer(Nc, 3); 248 *Nc = q->Nc; 249 } 250 if (npoints) { 251 PetscValidPointer(npoints, 4); 252 *npoints = q->numPoints; 253 } 254 if (points) { 255 PetscValidPointer(points, 5); 256 *points = q->points; 257 } 258 if (weights) { 259 PetscValidPointer(weights, 6); 260 *weights = q->weights; 261 } 262 PetscFunctionReturn(0); 263 } 264 265 /*@C 266 PetscQuadratureSetData - Sets the data defining the quadrature 267 268 Not collective 269 270 Input Parameters: 271 + q - The PetscQuadrature object 272 . dim - The spatial dimension 273 . Nc - The number of components 274 . npoints - The number of quadrature points 275 . points - The coordinates of each quadrature point 276 - weights - The weight of each quadrature point 277 278 Note: This routine owns the references to points and weights, so they must be allocated using PetscMalloc() and the user should not free them. 279 280 Level: intermediate 281 282 .seealso: PetscQuadratureCreate(), PetscQuadratureGetData() 283 @*/ 284 PetscErrorCode PetscQuadratureSetData(PetscQuadrature q, PetscInt dim, PetscInt Nc, PetscInt npoints, const PetscReal points[], const PetscReal weights[]) 285 { 286 PetscFunctionBegin; 287 PetscValidHeaderSpecific(q, PETSC_OBJECT_CLASSID, 1); 288 if (dim >= 0) q->dim = dim; 289 if (Nc >= 0) q->Nc = Nc; 290 if (npoints >= 0) q->numPoints = npoints; 291 if (points) { 292 PetscValidPointer(points, 4); 293 q->points = points; 294 } 295 if (weights) { 296 PetscValidPointer(weights, 5); 297 q->weights = weights; 298 } 299 PetscFunctionReturn(0); 300 } 301 302 static PetscErrorCode PetscQuadratureView_Ascii(PetscQuadrature quad, PetscViewer v) 303 { 304 PetscInt q, d, c; 305 PetscViewerFormat format; 306 PetscErrorCode ierr; 307 308 PetscFunctionBegin; 309 if (quad->Nc > 1) {ierr = PetscViewerASCIIPrintf(v, "Quadrature of order %D on %D points (dim %D) with %D components\n", quad->order, quad->numPoints, quad->dim, quad->Nc);CHKERRQ(ierr);} 310 else {ierr = PetscViewerASCIIPrintf(v, "Quadrature of order %D on %D points (dim %D)\n", quad->order, quad->numPoints, quad->dim);CHKERRQ(ierr);} 311 ierr = PetscViewerGetFormat(v, &format);CHKERRQ(ierr); 312 if (format != PETSC_VIEWER_ASCII_INFO_DETAIL) PetscFunctionReturn(0); 313 for (q = 0; q < quad->numPoints; ++q) { 314 ierr = PetscViewerASCIIPrintf(v, "p%D (", q);CHKERRQ(ierr); 315 ierr = PetscViewerASCIIUseTabs(v, PETSC_FALSE);CHKERRQ(ierr); 316 for (d = 0; d < quad->dim; ++d) { 317 if (d) {ierr = PetscViewerASCIIPrintf(v, ", ");CHKERRQ(ierr);} 318 ierr = PetscViewerASCIIPrintf(v, "%+g", (double)quad->points[q*quad->dim+d]);CHKERRQ(ierr); 319 } 320 ierr = PetscViewerASCIIPrintf(v, ") ");CHKERRQ(ierr); 321 if (quad->Nc > 1) {ierr = PetscViewerASCIIPrintf(v, "w%D (", q);CHKERRQ(ierr);} 322 for (c = 0; c < quad->Nc; ++c) { 323 if (c) {ierr = PetscViewerASCIIPrintf(v, ", ");CHKERRQ(ierr);} 324 ierr = PetscViewerASCIIPrintf(v, "%+g", (double)quad->weights[q*quad->Nc+c]);CHKERRQ(ierr); 325 } 326 if (quad->Nc > 1) {ierr = PetscViewerASCIIPrintf(v, ")");CHKERRQ(ierr);} 327 ierr = PetscViewerASCIIPrintf(v, "\n");CHKERRQ(ierr); 328 ierr = PetscViewerASCIIUseTabs(v, PETSC_TRUE);CHKERRQ(ierr); 329 } 330 PetscFunctionReturn(0); 331 } 332 333 /*@C 334 PetscQuadratureView - Views a PetscQuadrature object 335 336 Collective on PetscQuadrature 337 338 Input Parameters: 339 + quad - The PetscQuadrature object 340 - viewer - The PetscViewer object 341 342 Level: beginner 343 344 .seealso: PetscQuadratureCreate(), PetscQuadratureGetData() 345 @*/ 346 PetscErrorCode PetscQuadratureView(PetscQuadrature quad, PetscViewer viewer) 347 { 348 PetscBool iascii; 349 PetscErrorCode ierr; 350 351 PetscFunctionBegin; 352 PetscValidHeader(quad, 1); 353 if (viewer) PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 354 if (!viewer) {ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject) quad), &viewer);CHKERRQ(ierr);} 355 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr); 356 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 357 if (iascii) {ierr = PetscQuadratureView_Ascii(quad, viewer);CHKERRQ(ierr);} 358 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 359 PetscFunctionReturn(0); 360 } 361 362 /*@C 363 PetscQuadratureExpandComposite - Return a quadrature over the composite element, which has the original quadrature in each subelement 364 365 Not collective 366 367 Input Parameter: 368 + q - The original PetscQuadrature 369 . numSubelements - The number of subelements the original element is divided into 370 . v0 - An array of the initial points for each subelement 371 - jac - An array of the Jacobian mappings from the reference to each subelement 372 373 Output Parameters: 374 . dim - The dimension 375 376 Note: Together v0 and jac define an affine mapping from the original reference element to each subelement 377 378 Not available from Fortran 379 380 Level: intermediate 381 382 .seealso: PetscFECreate(), PetscSpaceGetDimension(), PetscDualSpaceGetDimension() 383 @*/ 384 PetscErrorCode PetscQuadratureExpandComposite(PetscQuadrature q, PetscInt numSubelements, const PetscReal v0[], const PetscReal jac[], PetscQuadrature *qref) 385 { 386 const PetscReal *points, *weights; 387 PetscReal *pointsRef, *weightsRef; 388 PetscInt dim, Nc, order, npoints, npointsRef, c, p, cp, d, e; 389 PetscErrorCode ierr; 390 391 PetscFunctionBegin; 392 PetscValidHeaderSpecific(q, PETSC_OBJECT_CLASSID, 1); 393 PetscValidPointer(v0, 3); 394 PetscValidPointer(jac, 4); 395 PetscValidPointer(qref, 5); 396 ierr = PetscQuadratureCreate(PETSC_COMM_SELF, qref);CHKERRQ(ierr); 397 ierr = PetscQuadratureGetOrder(q, &order);CHKERRQ(ierr); 398 ierr = PetscQuadratureGetData(q, &dim, &Nc, &npoints, &points, &weights);CHKERRQ(ierr); 399 npointsRef = npoints*numSubelements; 400 ierr = PetscMalloc1(npointsRef*dim,&pointsRef);CHKERRQ(ierr); 401 ierr = PetscMalloc1(npointsRef*Nc, &weightsRef);CHKERRQ(ierr); 402 for (c = 0; c < numSubelements; ++c) { 403 for (p = 0; p < npoints; ++p) { 404 for (d = 0; d < dim; ++d) { 405 pointsRef[(c*npoints + p)*dim+d] = v0[c*dim+d]; 406 for (e = 0; e < dim; ++e) { 407 pointsRef[(c*npoints + p)*dim+d] += jac[(c*dim + d)*dim+e]*(points[p*dim+e] + 1.0); 408 } 409 } 410 /* Could also use detJ here */ 411 for (cp = 0; cp < Nc; ++cp) weightsRef[(c*npoints+p)*Nc+cp] = weights[p*Nc+cp]/numSubelements; 412 } 413 } 414 ierr = PetscQuadratureSetOrder(*qref, order);CHKERRQ(ierr); 415 ierr = PetscQuadratureSetData(*qref, dim, Nc, npointsRef, pointsRef, weightsRef);CHKERRQ(ierr); 416 PetscFunctionReturn(0); 417 } 418 419 /*@ 420 PetscDTLegendreEval - evaluate Legendre polynomial at points 421 422 Not Collective 423 424 Input Arguments: 425 + npoints - number of spatial points to evaluate at 426 . points - array of locations to evaluate at 427 . ndegree - number of basis degrees to evaluate 428 - degrees - sorted array of degrees to evaluate 429 430 Output Arguments: 431 + B - row-oriented basis evaluation matrix B[point*ndegree + degree] (dimension npoints*ndegrees, allocated by caller) (or NULL) 432 . D - row-oriented derivative evaluation matrix (or NULL) 433 - D2 - row-oriented second derivative evaluation matrix (or NULL) 434 435 Level: intermediate 436 437 .seealso: PetscDTGaussQuadrature() 438 @*/ 439 PetscErrorCode PetscDTLegendreEval(PetscInt npoints,const PetscReal *points,PetscInt ndegree,const PetscInt *degrees,PetscReal *B,PetscReal *D,PetscReal *D2) 440 { 441 PetscInt i,maxdegree; 442 443 PetscFunctionBegin; 444 if (!npoints || !ndegree) PetscFunctionReturn(0); 445 maxdegree = degrees[ndegree-1]; 446 for (i=0; i<npoints; i++) { 447 PetscReal pm1,pm2,pd1,pd2,pdd1,pdd2,x; 448 PetscInt j,k; 449 x = points[i]; 450 pm2 = 0; 451 pm1 = 1; 452 pd2 = 0; 453 pd1 = 0; 454 pdd2 = 0; 455 pdd1 = 0; 456 k = 0; 457 if (degrees[k] == 0) { 458 if (B) B[i*ndegree+k] = pm1; 459 if (D) D[i*ndegree+k] = pd1; 460 if (D2) D2[i*ndegree+k] = pdd1; 461 k++; 462 } 463 for (j=1; j<=maxdegree; j++,k++) { 464 PetscReal p,d,dd; 465 p = ((2*j-1)*x*pm1 - (j-1)*pm2)/j; 466 d = pd2 + (2*j-1)*pm1; 467 dd = pdd2 + (2*j-1)*pd1; 468 pm2 = pm1; 469 pm1 = p; 470 pd2 = pd1; 471 pd1 = d; 472 pdd2 = pdd1; 473 pdd1 = dd; 474 if (degrees[k] == j) { 475 if (B) B[i*ndegree+k] = p; 476 if (D) D[i*ndegree+k] = d; 477 if (D2) D2[i*ndegree+k] = dd; 478 } 479 } 480 } 481 PetscFunctionReturn(0); 482 } 483 484 /*@ 485 PetscDTGaussQuadrature - create Gauss quadrature 486 487 Not Collective 488 489 Input Arguments: 490 + npoints - number of points 491 . a - left end of interval (often-1) 492 - b - right end of interval (often +1) 493 494 Output Arguments: 495 + x - quadrature points 496 - w - quadrature weights 497 498 Level: intermediate 499 500 References: 501 . 1. - Golub and Welsch, Calculation of Quadrature Rules, Math. Comp. 23(106), 1969. 502 503 .seealso: PetscDTLegendreEval() 504 @*/ 505 PetscErrorCode PetscDTGaussQuadrature(PetscInt npoints,PetscReal a,PetscReal b,PetscReal *x,PetscReal *w) 506 { 507 PetscErrorCode ierr; 508 PetscInt i; 509 PetscReal *work; 510 PetscScalar *Z; 511 PetscBLASInt N,LDZ,info; 512 513 PetscFunctionBegin; 514 ierr = PetscCitationsRegister(GaussCitation, &GaussCite);CHKERRQ(ierr); 515 /* Set up the Golub-Welsch system */ 516 for (i=0; i<npoints; i++) { 517 x[i] = 0; /* diagonal is 0 */ 518 if (i) w[i-1] = 0.5 / PetscSqrtReal(1 - 1./PetscSqr(2*i)); 519 } 520 ierr = PetscMalloc2(npoints*npoints,&Z,PetscMax(1,2*npoints-2),&work);CHKERRQ(ierr); 521 ierr = PetscBLASIntCast(npoints,&N);CHKERRQ(ierr); 522 LDZ = N; 523 ierr = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr); 524 PetscStackCallBLAS("LAPACKsteqr",LAPACKsteqr_("I",&N,x,w,Z,&LDZ,work,&info)); 525 ierr = PetscFPTrapPop();CHKERRQ(ierr); 526 if (info) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"xSTEQR error"); 527 528 for (i=0; i<(npoints+1)/2; i++) { 529 PetscReal y = 0.5 * (-x[i] + x[npoints-i-1]); /* enforces symmetry */ 530 x[i] = (a+b)/2 - y*(b-a)/2; 531 if (x[i] == -0.0) x[i] = 0.0; 532 x[npoints-i-1] = (a+b)/2 + y*(b-a)/2; 533 534 w[i] = w[npoints-1-i] = 0.5*(b-a)*(PetscSqr(PetscAbsScalar(Z[i*npoints])) + PetscSqr(PetscAbsScalar(Z[(npoints-i-1)*npoints]))); 535 } 536 ierr = PetscFree2(Z,work);CHKERRQ(ierr); 537 PetscFunctionReturn(0); 538 } 539 540 static void qAndLEvaluation(PetscInt n, PetscReal x, PetscReal *q, PetscReal *qp, PetscReal *Ln) 541 /* 542 Compute the polynomial q(x) = L_{N+1}(x) - L_{n-1}(x) and its derivative in 543 addition to L_N(x) as these are needed for computing the GLL points via Newton's method. 544 Reference: "Implementing Spectral Methods for Partial Differential Equations: Algorithms 545 for Scientists and Engineers" by David A. Kopriva. 546 */ 547 { 548 PetscInt k; 549 550 PetscReal Lnp; 551 PetscReal Lnp1, Lnp1p; 552 PetscReal Lnm1, Lnm1p; 553 PetscReal Lnm2, Lnm2p; 554 555 Lnm1 = 1.0; 556 *Ln = x; 557 Lnm1p = 0.0; 558 Lnp = 1.0; 559 560 for (k=2; k<=n; ++k) { 561 Lnm2 = Lnm1; 562 Lnm1 = *Ln; 563 Lnm2p = Lnm1p; 564 Lnm1p = Lnp; 565 *Ln = (2.*((PetscReal)k)-1.)/(1.0*((PetscReal)k))*x*Lnm1 - (((PetscReal)k)-1.)/((PetscReal)k)*Lnm2; 566 Lnp = Lnm2p + (2.0*((PetscReal)k)-1.)*Lnm1; 567 } 568 k = n+1; 569 Lnp1 = (2.*((PetscReal)k)-1.)/(((PetscReal)k))*x*(*Ln) - (((PetscReal)k)-1.)/((PetscReal)k)*Lnm1; 570 Lnp1p = Lnm1p + (2.0*((PetscReal)k)-1.)*(*Ln); 571 *q = Lnp1 - Lnm1; 572 *qp = Lnp1p - Lnm1p; 573 } 574 575 /*@C 576 PetscDTGaussLobattoLegendreQuadrature - creates a set of the locations and weights of the Gauss-Lobatto-Legendre 577 nodes of a given size on the domain [-1,1] 578 579 Not Collective 580 581 Input Parameter: 582 + n - number of grid nodes 583 - type - PETSCGAUSSLOBATTOLEGENDRE_VIA_LINEAR_ALGEBRA or PETSCGAUSSLOBATTOLEGENDRE_VIA_NEWTON 584 585 Output Arguments: 586 + x - quadrature points 587 - w - quadrature weights 588 589 Notes: 590 For n > 30 the Newton approach computes duplicate (incorrect) values for some nodes because the initial guess is apparently not 591 close enough to the desired solution 592 593 These are useful for implementing spectral methods based on Gauss-Lobatto-Legendre (GLL) nodes 594 595 See https://epubs.siam.org/doi/abs/10.1137/110855442 https://epubs.siam.org/doi/abs/10.1137/120889873 for better ways to compute GLL nodes 596 597 Level: intermediate 598 599 .seealso: PetscDTGaussQuadrature() 600 601 @*/ 602 PetscErrorCode PetscDTGaussLobattoLegendreQuadrature(PetscInt npoints,PetscGaussLobattoLegendreCreateType type,PetscReal *x,PetscReal *w) 603 { 604 PetscErrorCode ierr; 605 606 PetscFunctionBegin; 607 if (npoints < 2) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Must provide at least 2 grid points per element"); 608 609 if (type == PETSCGAUSSLOBATTOLEGENDRE_VIA_LINEAR_ALGEBRA) { 610 PetscReal *M,si; 611 PetscBLASInt bn,lierr; 612 PetscReal x0,z0,z1,z2; 613 PetscInt i,p = npoints - 1,nn; 614 615 x[0] =-1.0; 616 x[npoints-1] = 1.0; 617 if (npoints-2 > 0){ 618 ierr = PetscMalloc1(npoints-1,&M);CHKERRQ(ierr); 619 for (i=0; i<npoints-2; i++) { 620 si = ((PetscReal)i)+1.0; 621 M[i]=0.5*PetscSqrtReal(si*(si+2.0)/((si+0.5)*(si+1.5))); 622 } 623 ierr = PetscBLASIntCast(npoints-2,&bn);CHKERRQ(ierr); 624 ierr = PetscMemzero(&x[1],bn*sizeof(x[1]));CHKERRQ(ierr); 625 ierr = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr); 626 x0=0; 627 PetscStackCallBLAS("LAPACKsteqr",LAPACKREALsteqr_("N",&bn,&x[1],M,&x0,&bn,M,&lierr)); 628 if (lierr) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error in STERF Lapack routine %d",(int)lierr); 629 ierr = PetscFPTrapPop();CHKERRQ(ierr); 630 ierr = PetscFree(M);CHKERRQ(ierr); 631 } 632 if ((npoints-1)%2==0) { 633 x[(npoints-1)/2] = 0.0; /* hard wire to exactly 0.0 since linear algebra produces nonzero */ 634 } 635 636 w[0] = w[p] = 2.0/(((PetscReal)(p))*(((PetscReal)p)+1.0)); 637 z2 = -1.; /* Dummy value to avoid -Wmaybe-initialized */ 638 for (i=1; i<p; i++) { 639 x0 = x[i]; 640 z0 = 1.0; 641 z1 = x0; 642 for (nn=1; nn<p; nn++) { 643 z2 = x0*z1*(2.0*((PetscReal)nn)+1.0)/(((PetscReal)nn)+1.0)-z0*(((PetscReal)nn)/(((PetscReal)nn)+1.0)); 644 z0 = z1; 645 z1 = z2; 646 } 647 w[i]=2.0/(((PetscReal)p)*(((PetscReal)p)+1.0)*z2*z2); 648 } 649 } else { 650 PetscInt j,m; 651 PetscReal z1,z,q,qp,Ln; 652 PetscReal *pt; 653 ierr = PetscMalloc1(npoints,&pt);CHKERRQ(ierr); 654 655 if (npoints > 30) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"PETSCGAUSSLOBATTOLEGENDRE_VIA_NEWTON produces incorrect answers for n > 30"); 656 x[0] = -1.0; 657 x[npoints-1] = 1.0; 658 w[0] = w[npoints-1] = 2./(((PetscReal)npoints)*(((PetscReal)npoints)-1.0));; 659 m = (npoints-1)/2; /* The roots are symmetric, so we only find half of them. */ 660 for (j=1; j<=m; j++) { /* Loop over the desired roots. */ 661 z = -1.0*PetscCosReal((PETSC_PI*((PetscReal)j)+0.25)/(((PetscReal)npoints)-1.0))-(3.0/(8.0*(((PetscReal)npoints)-1.0)*PETSC_PI))*(1.0/(((PetscReal)j)+0.25)); 662 /* Starting with the above approximation to the ith root, we enter */ 663 /* the main loop of refinement by Newton's method. */ 664 do { 665 qAndLEvaluation(npoints-1,z,&q,&qp,&Ln); 666 z1 = z; 667 z = z1-q/qp; /* Newton's method. */ 668 } while (PetscAbs(z-z1) > 10.*PETSC_MACHINE_EPSILON); 669 qAndLEvaluation(npoints-1,z,&q,&qp,&Ln); 670 671 x[j] = z; 672 x[npoints-1-j] = -z; /* and put in its symmetric counterpart. */ 673 w[j] = 2.0/(((PetscReal)npoints)*(((PetscReal)npoints)-1.)*Ln*Ln); /* Compute the weight */ 674 w[npoints-1-j] = w[j]; /* and its symmetric counterpart. */ 675 pt[j]=qp; 676 } 677 678 if ((npoints-1)%2==0) { 679 qAndLEvaluation(npoints-1,0.0,&q,&qp,&Ln); 680 x[(npoints-1)/2] = 0.0; 681 w[(npoints-1)/2] = 2.0/(((PetscReal)npoints)*(((PetscReal)npoints)-1.)*Ln*Ln); 682 } 683 ierr = PetscFree(pt);CHKERRQ(ierr); 684 } 685 PetscFunctionReturn(0); 686 } 687 688 /*@ 689 PetscDTGaussTensorQuadrature - creates a tensor-product Gauss quadrature 690 691 Not Collective 692 693 Input Arguments: 694 + dim - The spatial dimension 695 . Nc - The number of components 696 . npoints - number of points in one dimension 697 . a - left end of interval (often-1) 698 - b - right end of interval (often +1) 699 700 Output Argument: 701 . q - A PetscQuadrature object 702 703 Level: intermediate 704 705 .seealso: PetscDTGaussQuadrature(), PetscDTLegendreEval() 706 @*/ 707 PetscErrorCode PetscDTGaussTensorQuadrature(PetscInt dim, PetscInt Nc, PetscInt npoints, PetscReal a, PetscReal b, PetscQuadrature *q) 708 { 709 PetscInt totpoints = dim > 1 ? dim > 2 ? npoints*PetscSqr(npoints) : PetscSqr(npoints) : npoints, i, j, k, c; 710 PetscReal *x, *w, *xw, *ww; 711 PetscErrorCode ierr; 712 713 PetscFunctionBegin; 714 ierr = PetscMalloc1(totpoints*dim,&x);CHKERRQ(ierr); 715 ierr = PetscMalloc1(totpoints*Nc,&w);CHKERRQ(ierr); 716 /* Set up the Golub-Welsch system */ 717 switch (dim) { 718 case 0: 719 ierr = PetscFree(x);CHKERRQ(ierr); 720 ierr = PetscFree(w);CHKERRQ(ierr); 721 ierr = PetscMalloc1(1, &x);CHKERRQ(ierr); 722 ierr = PetscMalloc1(Nc, &w);CHKERRQ(ierr); 723 x[0] = 0.0; 724 for (c = 0; c < Nc; ++c) w[c] = 1.0; 725 break; 726 case 1: 727 ierr = PetscMalloc1(npoints,&ww);CHKERRQ(ierr); 728 ierr = PetscDTGaussQuadrature(npoints, a, b, x, ww);CHKERRQ(ierr); 729 for (i = 0; i < npoints; ++i) for (c = 0; c < Nc; ++c) w[i*Nc+c] = ww[i]; 730 ierr = PetscFree(ww);CHKERRQ(ierr); 731 break; 732 case 2: 733 ierr = PetscMalloc2(npoints,&xw,npoints,&ww);CHKERRQ(ierr); 734 ierr = PetscDTGaussQuadrature(npoints, a, b, xw, ww);CHKERRQ(ierr); 735 for (i = 0; i < npoints; ++i) { 736 for (j = 0; j < npoints; ++j) { 737 x[(i*npoints+j)*dim+0] = xw[i]; 738 x[(i*npoints+j)*dim+1] = xw[j]; 739 for (c = 0; c < Nc; ++c) w[(i*npoints+j)*Nc+c] = ww[i] * ww[j]; 740 } 741 } 742 ierr = PetscFree2(xw,ww);CHKERRQ(ierr); 743 break; 744 case 3: 745 ierr = PetscMalloc2(npoints,&xw,npoints,&ww);CHKERRQ(ierr); 746 ierr = PetscDTGaussQuadrature(npoints, a, b, xw, ww);CHKERRQ(ierr); 747 for (i = 0; i < npoints; ++i) { 748 for (j = 0; j < npoints; ++j) { 749 for (k = 0; k < npoints; ++k) { 750 x[((i*npoints+j)*npoints+k)*dim+0] = xw[i]; 751 x[((i*npoints+j)*npoints+k)*dim+1] = xw[j]; 752 x[((i*npoints+j)*npoints+k)*dim+2] = xw[k]; 753 for (c = 0; c < Nc; ++c) w[((i*npoints+j)*npoints+k)*Nc+c] = ww[i] * ww[j] * ww[k]; 754 } 755 } 756 } 757 ierr = PetscFree2(xw,ww);CHKERRQ(ierr); 758 break; 759 default: 760 SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct quadrature rule for dimension %d", dim); 761 } 762 ierr = PetscQuadratureCreate(PETSC_COMM_SELF, q);CHKERRQ(ierr); 763 ierr = PetscQuadratureSetOrder(*q, 2*npoints-1);CHKERRQ(ierr); 764 ierr = PetscQuadratureSetData(*q, dim, Nc, totpoints, x, w);CHKERRQ(ierr); 765 ierr = PetscObjectChangeTypeName((PetscObject)*q,"GaussTensor");CHKERRQ(ierr); 766 PetscFunctionReturn(0); 767 } 768 769 /* Evaluates the nth jacobi polynomial with weight parameters a,b at a point x. 770 Recurrence relations implemented from the pseudocode given in Karniadakis and Sherwin, Appendix B */ 771 PETSC_STATIC_INLINE PetscErrorCode PetscDTFactorial_Internal(PetscInt n, PetscReal *factorial) 772 { 773 PetscReal f = 1.0; 774 PetscInt i; 775 776 PetscFunctionBegin; 777 for (i = 1; i < n+1; ++i) f *= i; 778 *factorial = f; 779 PetscFunctionReturn(0); 780 } 781 782 /* Evaluates the nth jacobi polynomial with weight parameters a,b at a point x. 783 Recurrence relations implemented from the pseudocode given in Karniadakis and Sherwin, Appendix B */ 784 PETSC_STATIC_INLINE PetscErrorCode PetscDTComputeJacobi(PetscReal a, PetscReal b, PetscInt n, PetscReal x, PetscReal *P) 785 { 786 PetscReal apb, pn1, pn2; 787 PetscInt k; 788 789 PetscFunctionBegin; 790 if (!n) {*P = 1.0; PetscFunctionReturn(0);} 791 if (n == 1) {*P = 0.5 * (a - b + (a + b + 2.0) * x); PetscFunctionReturn(0);} 792 apb = a + b; 793 pn2 = 1.0; 794 pn1 = 0.5 * (a - b + (apb + 2.0) * x); 795 *P = 0.0; 796 for (k = 2; k < n+1; ++k) { 797 PetscReal a1 = 2.0 * k * (k + apb) * (2.0*k + apb - 2.0); 798 PetscReal a2 = (2.0 * k + apb - 1.0) * (a*a - b*b); 799 PetscReal a3 = (2.0 * k + apb - 2.0) * (2.0 * k + apb - 1.0) * (2.0 * k + apb); 800 PetscReal a4 = 2.0 * (k + a - 1.0) * (k + b - 1.0) * (2.0 * k + apb); 801 802 a2 = a2 / a1; 803 a3 = a3 / a1; 804 a4 = a4 / a1; 805 *P = (a2 + a3 * x) * pn1 - a4 * pn2; 806 pn2 = pn1; 807 pn1 = *P; 808 } 809 PetscFunctionReturn(0); 810 } 811 812 /* Evaluates the first derivative of P_{n}^{a,b} at a point x. */ 813 PETSC_STATIC_INLINE PetscErrorCode PetscDTComputeJacobiDerivative(PetscReal a, PetscReal b, PetscInt n, PetscReal x, PetscReal *P) 814 { 815 PetscReal nP; 816 PetscErrorCode ierr; 817 818 PetscFunctionBegin; 819 if (!n) {*P = 0.0; PetscFunctionReturn(0);} 820 ierr = PetscDTComputeJacobi(a+1, b+1, n-1, x, &nP);CHKERRQ(ierr); 821 *P = 0.5 * (a + b + n + 1) * nP; 822 PetscFunctionReturn(0); 823 } 824 825 /* Maps from [-1,1]^2 to the (-1,1) reference triangle */ 826 PETSC_STATIC_INLINE PetscErrorCode PetscDTMapSquareToTriangle_Internal(PetscReal x, PetscReal y, PetscReal *xi, PetscReal *eta) 827 { 828 PetscFunctionBegin; 829 *xi = 0.5 * (1.0 + x) * (1.0 - y) - 1.0; 830 *eta = y; 831 PetscFunctionReturn(0); 832 } 833 834 /* Maps from [-1,1]^2 to the (-1,1) reference triangle */ 835 PETSC_STATIC_INLINE PetscErrorCode PetscDTMapCubeToTetrahedron_Internal(PetscReal x, PetscReal y, PetscReal z, PetscReal *xi, PetscReal *eta, PetscReal *zeta) 836 { 837 PetscFunctionBegin; 838 *xi = 0.25 * (1.0 + x) * (1.0 - y) * (1.0 - z) - 1.0; 839 *eta = 0.5 * (1.0 + y) * (1.0 - z) - 1.0; 840 *zeta = z; 841 PetscFunctionReturn(0); 842 } 843 844 static PetscErrorCode PetscDTGaussJacobiQuadrature1D_Internal(PetscInt npoints, PetscReal a, PetscReal b, PetscReal *x, PetscReal *w) 845 { 846 PetscInt maxIter = 100; 847 PetscReal eps = 1.0e-8; 848 PetscReal a1, a2, a3, a4, a5, a6; 849 PetscInt k; 850 PetscErrorCode ierr; 851 852 PetscFunctionBegin; 853 854 a1 = PetscPowReal(2.0, a+b+1); 855 #if defined(PETSC_HAVE_TGAMMA) 856 a2 = PetscTGamma(a + npoints + 1); 857 a3 = PetscTGamma(b + npoints + 1); 858 a4 = PetscTGamma(a + b + npoints + 1); 859 #else 860 { 861 PetscInt ia, ib; 862 863 ia = (PetscInt) a; 864 ib = (PetscInt) b; 865 if (ia == a && ib == b && ia + npoints + 1 > 0 && ib + npoints + 1 > 0 && ia + ib + npoints + 1 > 0) { /* All gamma(x) terms are (x-1)! terms */ 866 ierr = PetscDTFactorial_Internal(ia + npoints, &a2);CHKERRQ(ierr); 867 ierr = PetscDTFactorial_Internal(ib + npoints, &a3);CHKERRQ(ierr); 868 ierr = PetscDTFactorial_Internal(ia + ib + npoints, &a4);CHKERRQ(ierr); 869 } else { 870 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"tgamma() - math routine is unavailable."); 871 } 872 } 873 #endif 874 875 ierr = PetscDTFactorial_Internal(npoints, &a5);CHKERRQ(ierr); 876 a6 = a1 * a2 * a3 / a4 / a5; 877 /* Computes the m roots of P_{m}^{a,b} on [-1,1] by Newton's method with Chebyshev points as initial guesses. 878 Algorithm implemented from the pseudocode given by Karniadakis and Sherwin and Python in FIAT */ 879 for (k = 0; k < npoints; ++k) { 880 PetscReal r = -PetscCosReal((2.0*k + 1.0) * PETSC_PI / (2.0 * npoints)), dP; 881 PetscInt j; 882 883 if (k > 0) r = 0.5 * (r + x[k-1]); 884 for (j = 0; j < maxIter; ++j) { 885 PetscReal s = 0.0, delta, f, fp; 886 PetscInt i; 887 888 for (i = 0; i < k; ++i) s = s + 1.0 / (r - x[i]); 889 ierr = PetscDTComputeJacobi(a, b, npoints, r, &f);CHKERRQ(ierr); 890 ierr = PetscDTComputeJacobiDerivative(a, b, npoints, r, &fp);CHKERRQ(ierr); 891 delta = f / (fp - f * s); 892 r = r - delta; 893 if (PetscAbsReal(delta) < eps) break; 894 } 895 x[k] = r; 896 ierr = PetscDTComputeJacobiDerivative(a, b, npoints, x[k], &dP);CHKERRQ(ierr); 897 w[k] = a6 / (1.0 - PetscSqr(x[k])) / PetscSqr(dP); 898 } 899 PetscFunctionReturn(0); 900 } 901 902 /*@ 903 PetscDTGaussJacobiQuadrature - create Gauss-Jacobi quadrature for a simplex 904 905 Not Collective 906 907 Input Arguments: 908 + dim - The simplex dimension 909 . Nc - The number of components 910 . npoints - The number of points in one dimension 911 . a - left end of interval (often-1) 912 - b - right end of interval (often +1) 913 914 Output Argument: 915 . q - A PetscQuadrature object 916 917 Level: intermediate 918 919 References: 920 . 1. - Karniadakis and Sherwin. FIAT 921 922 .seealso: PetscDTGaussTensorQuadrature(), PetscDTGaussQuadrature() 923 @*/ 924 PetscErrorCode PetscDTGaussJacobiQuadrature(PetscInt dim, PetscInt Nc, PetscInt npoints, PetscReal a, PetscReal b, PetscQuadrature *q) 925 { 926 PetscInt totpoints = dim > 1 ? dim > 2 ? npoints*PetscSqr(npoints) : PetscSqr(npoints) : npoints; 927 PetscReal *px, *wx, *py, *wy, *pz, *wz, *x, *w; 928 PetscInt i, j, k, c; 929 PetscErrorCode ierr; 930 931 PetscFunctionBegin; 932 if ((a != -1.0) || (b != 1.0)) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must use default internal right now"); 933 ierr = PetscMalloc1(totpoints*dim, &x);CHKERRQ(ierr); 934 ierr = PetscMalloc1(totpoints*Nc, &w);CHKERRQ(ierr); 935 switch (dim) { 936 case 0: 937 ierr = PetscFree(x);CHKERRQ(ierr); 938 ierr = PetscFree(w);CHKERRQ(ierr); 939 ierr = PetscMalloc1(1, &x);CHKERRQ(ierr); 940 ierr = PetscMalloc1(Nc, &w);CHKERRQ(ierr); 941 x[0] = 0.0; 942 for (c = 0; c < Nc; ++c) w[c] = 1.0; 943 break; 944 case 1: 945 ierr = PetscMalloc1(npoints,&wx);CHKERRQ(ierr); 946 ierr = PetscDTGaussJacobiQuadrature1D_Internal(npoints, 0.0, 0.0, x, wx);CHKERRQ(ierr); 947 for (i = 0; i < npoints; ++i) for (c = 0; c < Nc; ++c) w[i*Nc+c] = wx[i]; 948 ierr = PetscFree(wx);CHKERRQ(ierr); 949 break; 950 case 2: 951 ierr = PetscMalloc4(npoints,&px,npoints,&wx,npoints,&py,npoints,&wy);CHKERRQ(ierr); 952 ierr = PetscDTGaussJacobiQuadrature1D_Internal(npoints, 0.0, 0.0, px, wx);CHKERRQ(ierr); 953 ierr = PetscDTGaussJacobiQuadrature1D_Internal(npoints, 1.0, 0.0, py, wy);CHKERRQ(ierr); 954 for (i = 0; i < npoints; ++i) { 955 for (j = 0; j < npoints; ++j) { 956 ierr = PetscDTMapSquareToTriangle_Internal(px[i], py[j], &x[(i*npoints+j)*2+0], &x[(i*npoints+j)*2+1]);CHKERRQ(ierr); 957 for (c = 0; c < Nc; ++c) w[(i*npoints+j)*Nc+c] = 0.5 * wx[i] * wy[j]; 958 } 959 } 960 ierr = PetscFree4(px,wx,py,wy);CHKERRQ(ierr); 961 break; 962 case 3: 963 ierr = PetscMalloc6(npoints,&px,npoints,&wx,npoints,&py,npoints,&wy,npoints,&pz,npoints,&wz);CHKERRQ(ierr); 964 ierr = PetscDTGaussJacobiQuadrature1D_Internal(npoints, 0.0, 0.0, px, wx);CHKERRQ(ierr); 965 ierr = PetscDTGaussJacobiQuadrature1D_Internal(npoints, 1.0, 0.0, py, wy);CHKERRQ(ierr); 966 ierr = PetscDTGaussJacobiQuadrature1D_Internal(npoints, 2.0, 0.0, pz, wz);CHKERRQ(ierr); 967 for (i = 0; i < npoints; ++i) { 968 for (j = 0; j < npoints; ++j) { 969 for (k = 0; k < npoints; ++k) { 970 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); 971 for (c = 0; c < Nc; ++c) w[((i*npoints+j)*npoints+k)*Nc+c] = 0.125 * wx[i] * wy[j] * wz[k]; 972 } 973 } 974 } 975 ierr = PetscFree6(px,wx,py,wy,pz,wz);CHKERRQ(ierr); 976 break; 977 default: 978 SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct quadrature rule for dimension %d", dim); 979 } 980 ierr = PetscQuadratureCreate(PETSC_COMM_SELF, q);CHKERRQ(ierr); 981 ierr = PetscQuadratureSetOrder(*q, 2*npoints-1);CHKERRQ(ierr); 982 ierr = PetscQuadratureSetData(*q, dim, Nc, totpoints, x, w);CHKERRQ(ierr); 983 ierr = PetscObjectChangeTypeName((PetscObject)*q,"GaussJacobi");CHKERRQ(ierr); 984 PetscFunctionReturn(0); 985 } 986 987 /*@ 988 PetscDTTanhSinhTensorQuadrature - create tanh-sinh quadrature for a tensor product cell 989 990 Not Collective 991 992 Input Arguments: 993 + dim - The cell dimension 994 . level - The number of points in one dimension, 2^l 995 . a - left end of interval (often-1) 996 - b - right end of interval (often +1) 997 998 Output Argument: 999 . q - A PetscQuadrature object 1000 1001 Level: intermediate 1002 1003 .seealso: PetscDTGaussTensorQuadrature() 1004 @*/ 1005 PetscErrorCode PetscDTTanhSinhTensorQuadrature(PetscInt dim, PetscInt level, PetscReal a, PetscReal b, PetscQuadrature *q) 1006 { 1007 const PetscInt p = 16; /* Digits of precision in the evaluation */ 1008 const PetscReal alpha = (b-a)/2.; /* Half-width of the integration interval */ 1009 const PetscReal beta = (b+a)/2.; /* Center of the integration interval */ 1010 const PetscReal h = PetscPowReal(2.0, -level); /* Step size, length between x_k */ 1011 PetscReal xk; /* Quadrature point x_k on reference domain [-1, 1] */ 1012 PetscReal wk = 0.5*PETSC_PI; /* Quadrature weight at x_k */ 1013 PetscReal *x, *w; 1014 PetscInt K, k, npoints; 1015 PetscErrorCode ierr; 1016 1017 PetscFunctionBegin; 1018 if (dim > 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Dimension %d not yet implemented", dim); 1019 if (!level) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must give a number of significant digits"); 1020 /* Find K such that the weights are < 32 digits of precision */ 1021 for (K = 1; PetscAbsReal(PetscLog10Real(wk)) < 2*p; ++K) { 1022 wk = 0.5*h*PETSC_PI*PetscCoshReal(K*h)/PetscSqr(PetscCoshReal(0.5*PETSC_PI*PetscSinhReal(K*h))); 1023 } 1024 ierr = PetscQuadratureCreate(PETSC_COMM_SELF, q);CHKERRQ(ierr); 1025 ierr = PetscQuadratureSetOrder(*q, 2*K+1);CHKERRQ(ierr); 1026 npoints = 2*K-1; 1027 ierr = PetscMalloc1(npoints*dim, &x);CHKERRQ(ierr); 1028 ierr = PetscMalloc1(npoints, &w);CHKERRQ(ierr); 1029 /* Center term */ 1030 x[0] = beta; 1031 w[0] = 0.5*alpha*PETSC_PI; 1032 for (k = 1; k < K; ++k) { 1033 wk = 0.5*alpha*h*PETSC_PI*PetscCoshReal(k*h)/PetscSqr(PetscCoshReal(0.5*PETSC_PI*PetscSinhReal(k*h))); 1034 xk = PetscTanhReal(0.5*PETSC_PI*PetscSinhReal(k*h)); 1035 x[2*k-1] = -alpha*xk+beta; 1036 w[2*k-1] = wk; 1037 x[2*k+0] = alpha*xk+beta; 1038 w[2*k+0] = wk; 1039 } 1040 ierr = PetscQuadratureSetData(*q, dim, 1, npoints, x, w);CHKERRQ(ierr); 1041 PetscFunctionReturn(0); 1042 } 1043 1044 PetscErrorCode PetscDTTanhSinhIntegrate(void (*func)(PetscReal, PetscReal *), PetscReal a, PetscReal b, PetscInt digits, PetscReal *sol) 1045 { 1046 const PetscInt p = 16; /* Digits of precision in the evaluation */ 1047 const PetscReal alpha = (b-a)/2.; /* Half-width of the integration interval */ 1048 const PetscReal beta = (b+a)/2.; /* Center of the integration interval */ 1049 PetscReal h = 1.0; /* Step size, length between x_k */ 1050 PetscInt l = 0; /* Level of refinement, h = 2^{-l} */ 1051 PetscReal osum = 0.0; /* Integral on last level */ 1052 PetscReal psum = 0.0; /* Integral on the level before the last level */ 1053 PetscReal sum; /* Integral on current level */ 1054 PetscReal yk; /* Quadrature point 1 - x_k on reference domain [-1, 1] */ 1055 PetscReal lx, rx; /* Quadrature points to the left and right of 0 on the real domain [a, b] */ 1056 PetscReal wk; /* Quadrature weight at x_k */ 1057 PetscReal lval, rval; /* Terms in the quadature sum to the left and right of 0 */ 1058 PetscInt d; /* Digits of precision in the integral */ 1059 1060 PetscFunctionBegin; 1061 if (digits <= 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must give a positive number of significant digits"); 1062 /* Center term */ 1063 func(beta, &lval); 1064 sum = 0.5*alpha*PETSC_PI*lval; 1065 /* */ 1066 do { 1067 PetscReal lterm, rterm, maxTerm = 0.0, d1, d2, d3, d4; 1068 PetscInt k = 1; 1069 1070 ++l; 1071 /* PetscPrintf(PETSC_COMM_SELF, "LEVEL %D sum: %15.15f\n", l, sum); */ 1072 /* At each level of refinement, h --> h/2 and sum --> sum/2 */ 1073 psum = osum; 1074 osum = sum; 1075 h *= 0.5; 1076 sum *= 0.5; 1077 do { 1078 wk = 0.5*h*PETSC_PI*PetscCoshReal(k*h)/PetscSqr(PetscCoshReal(0.5*PETSC_PI*PetscSinhReal(k*h))); 1079 yk = 1.0/(PetscExpReal(0.5*PETSC_PI*PetscSinhReal(k*h)) * PetscCoshReal(0.5*PETSC_PI*PetscSinhReal(k*h))); 1080 lx = -alpha*(1.0 - yk)+beta; 1081 rx = alpha*(1.0 - yk)+beta; 1082 func(lx, &lval); 1083 func(rx, &rval); 1084 lterm = alpha*wk*lval; 1085 maxTerm = PetscMax(PetscAbsReal(lterm), maxTerm); 1086 sum += lterm; 1087 rterm = alpha*wk*rval; 1088 maxTerm = PetscMax(PetscAbsReal(rterm), maxTerm); 1089 sum += rterm; 1090 ++k; 1091 /* Only need to evaluate every other point on refined levels */ 1092 if (l != 1) ++k; 1093 } while (PetscAbsReal(PetscLog10Real(wk)) < p); /* Only need to evaluate sum until weights are < 32 digits of precision */ 1094 1095 d1 = PetscLog10Real(PetscAbsReal(sum - osum)); 1096 d2 = PetscLog10Real(PetscAbsReal(sum - psum)); 1097 d3 = PetscLog10Real(maxTerm) - p; 1098 if (PetscMax(PetscAbsReal(lterm), PetscAbsReal(rterm)) == 0.0) d4 = 0.0; 1099 else d4 = PetscLog10Real(PetscMax(PetscAbsReal(lterm), PetscAbsReal(rterm))); 1100 d = PetscAbsInt(PetscMin(0, PetscMax(PetscMax(PetscMax(PetscSqr(d1)/d2, 2*d1), d3), d4))); 1101 } while (d < digits && l < 12); 1102 *sol = sum; 1103 1104 PetscFunctionReturn(0); 1105 } 1106 1107 #if defined(PETSC_HAVE_MPFR) 1108 PetscErrorCode PetscDTTanhSinhIntegrateMPFR(void (*func)(PetscReal, PetscReal *), PetscReal a, PetscReal b, PetscInt digits, PetscReal *sol) 1109 { 1110 const PetscInt safetyFactor = 2; /* Calculate abcissa until 2*p digits */ 1111 PetscInt l = 0; /* Level of refinement, h = 2^{-l} */ 1112 mpfr_t alpha; /* Half-width of the integration interval */ 1113 mpfr_t beta; /* Center of the integration interval */ 1114 mpfr_t h; /* Step size, length between x_k */ 1115 mpfr_t osum; /* Integral on last level */ 1116 mpfr_t psum; /* Integral on the level before the last level */ 1117 mpfr_t sum; /* Integral on current level */ 1118 mpfr_t yk; /* Quadrature point 1 - x_k on reference domain [-1, 1] */ 1119 mpfr_t lx, rx; /* Quadrature points to the left and right of 0 on the real domain [a, b] */ 1120 mpfr_t wk; /* Quadrature weight at x_k */ 1121 PetscReal lval, rval; /* Terms in the quadature sum to the left and right of 0 */ 1122 PetscInt d; /* Digits of precision in the integral */ 1123 mpfr_t pi2, kh, msinh, mcosh, maxTerm, curTerm, tmp; 1124 1125 PetscFunctionBegin; 1126 if (digits <= 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must give a positive number of significant digits"); 1127 /* Create high precision storage */ 1128 mpfr_inits2(PetscCeilReal(safetyFactor*digits*PetscLogReal(10.)/PetscLogReal(2.)), alpha, beta, h, sum, osum, psum, yk, wk, lx, rx, tmp, maxTerm, curTerm, pi2, kh, msinh, mcosh, NULL); 1129 /* Initialization */ 1130 mpfr_set_d(alpha, 0.5*(b-a), MPFR_RNDN); 1131 mpfr_set_d(beta, 0.5*(b+a), MPFR_RNDN); 1132 mpfr_set_d(osum, 0.0, MPFR_RNDN); 1133 mpfr_set_d(psum, 0.0, MPFR_RNDN); 1134 mpfr_set_d(h, 1.0, MPFR_RNDN); 1135 mpfr_const_pi(pi2, MPFR_RNDN); 1136 mpfr_mul_d(pi2, pi2, 0.5, MPFR_RNDN); 1137 /* Center term */ 1138 func(0.5*(b+a), &lval); 1139 mpfr_set(sum, pi2, MPFR_RNDN); 1140 mpfr_mul(sum, sum, alpha, MPFR_RNDN); 1141 mpfr_mul_d(sum, sum, lval, MPFR_RNDN); 1142 /* */ 1143 do { 1144 PetscReal d1, d2, d3, d4; 1145 PetscInt k = 1; 1146 1147 ++l; 1148 mpfr_set_d(maxTerm, 0.0, MPFR_RNDN); 1149 /* PetscPrintf(PETSC_COMM_SELF, "LEVEL %D sum: %15.15f\n", l, sum); */ 1150 /* At each level of refinement, h --> h/2 and sum --> sum/2 */ 1151 mpfr_set(psum, osum, MPFR_RNDN); 1152 mpfr_set(osum, sum, MPFR_RNDN); 1153 mpfr_mul_d(h, h, 0.5, MPFR_RNDN); 1154 mpfr_mul_d(sum, sum, 0.5, MPFR_RNDN); 1155 do { 1156 mpfr_set_si(kh, k, MPFR_RNDN); 1157 mpfr_mul(kh, kh, h, MPFR_RNDN); 1158 /* Weight */ 1159 mpfr_set(wk, h, MPFR_RNDN); 1160 mpfr_sinh_cosh(msinh, mcosh, kh, MPFR_RNDN); 1161 mpfr_mul(msinh, msinh, pi2, MPFR_RNDN); 1162 mpfr_mul(mcosh, mcosh, pi2, MPFR_RNDN); 1163 mpfr_cosh(tmp, msinh, MPFR_RNDN); 1164 mpfr_sqr(tmp, tmp, MPFR_RNDN); 1165 mpfr_mul(wk, wk, mcosh, MPFR_RNDN); 1166 mpfr_div(wk, wk, tmp, MPFR_RNDN); 1167 /* Abscissa */ 1168 mpfr_set_d(yk, 1.0, MPFR_RNDZ); 1169 mpfr_cosh(tmp, msinh, MPFR_RNDN); 1170 mpfr_div(yk, yk, tmp, MPFR_RNDZ); 1171 mpfr_exp(tmp, msinh, MPFR_RNDN); 1172 mpfr_div(yk, yk, tmp, MPFR_RNDZ); 1173 /* Quadrature points */ 1174 mpfr_sub_d(lx, yk, 1.0, MPFR_RNDZ); 1175 mpfr_mul(lx, lx, alpha, MPFR_RNDU); 1176 mpfr_add(lx, lx, beta, MPFR_RNDU); 1177 mpfr_d_sub(rx, 1.0, yk, MPFR_RNDZ); 1178 mpfr_mul(rx, rx, alpha, MPFR_RNDD); 1179 mpfr_add(rx, rx, beta, MPFR_RNDD); 1180 /* Evaluation */ 1181 func(mpfr_get_d(lx, MPFR_RNDU), &lval); 1182 func(mpfr_get_d(rx, MPFR_RNDD), &rval); 1183 /* Update */ 1184 mpfr_mul(tmp, wk, alpha, MPFR_RNDN); 1185 mpfr_mul_d(tmp, tmp, lval, MPFR_RNDN); 1186 mpfr_add(sum, sum, tmp, MPFR_RNDN); 1187 mpfr_abs(tmp, tmp, MPFR_RNDN); 1188 mpfr_max(maxTerm, maxTerm, tmp, MPFR_RNDN); 1189 mpfr_set(curTerm, tmp, MPFR_RNDN); 1190 mpfr_mul(tmp, wk, alpha, MPFR_RNDN); 1191 mpfr_mul_d(tmp, tmp, rval, MPFR_RNDN); 1192 mpfr_add(sum, sum, tmp, MPFR_RNDN); 1193 mpfr_abs(tmp, tmp, MPFR_RNDN); 1194 mpfr_max(maxTerm, maxTerm, tmp, MPFR_RNDN); 1195 mpfr_max(curTerm, curTerm, tmp, MPFR_RNDN); 1196 ++k; 1197 /* Only need to evaluate every other point on refined levels */ 1198 if (l != 1) ++k; 1199 mpfr_log10(tmp, wk, MPFR_RNDN); 1200 mpfr_abs(tmp, tmp, MPFR_RNDN); 1201 } while (mpfr_get_d(tmp, MPFR_RNDN) < safetyFactor*digits); /* Only need to evaluate sum until weights are < 32 digits of precision */ 1202 mpfr_sub(tmp, sum, osum, MPFR_RNDN); 1203 mpfr_abs(tmp, tmp, MPFR_RNDN); 1204 mpfr_log10(tmp, tmp, MPFR_RNDN); 1205 d1 = mpfr_get_d(tmp, MPFR_RNDN); 1206 mpfr_sub(tmp, sum, psum, MPFR_RNDN); 1207 mpfr_abs(tmp, tmp, MPFR_RNDN); 1208 mpfr_log10(tmp, tmp, MPFR_RNDN); 1209 d2 = mpfr_get_d(tmp, MPFR_RNDN); 1210 mpfr_log10(tmp, maxTerm, MPFR_RNDN); 1211 d3 = mpfr_get_d(tmp, MPFR_RNDN) - digits; 1212 mpfr_log10(tmp, curTerm, MPFR_RNDN); 1213 d4 = mpfr_get_d(tmp, MPFR_RNDN); 1214 d = PetscAbsInt(PetscMin(0, PetscMax(PetscMax(PetscMax(PetscSqr(d1)/d2, 2*d1), d3), d4))); 1215 } while (d < digits && l < 8); 1216 *sol = mpfr_get_d(sum, MPFR_RNDN); 1217 /* Cleanup */ 1218 mpfr_clears(alpha, beta, h, sum, osum, psum, yk, wk, lx, rx, tmp, maxTerm, curTerm, pi2, kh, msinh, mcosh, NULL); 1219 PetscFunctionReturn(0); 1220 } 1221 #else 1222 1223 PetscErrorCode PetscDTTanhSinhIntegrateMPFR(void (*func)(PetscReal, PetscReal *), PetscReal a, PetscReal b, PetscInt digits, PetscReal *sol) 1224 { 1225 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "This method will not work without MPFR. Reconfigure using --download-mpfr --download-gmp"); 1226 } 1227 #endif 1228 1229 /* Overwrites A. Can only handle full-rank problems with m>=n 1230 * A in column-major format 1231 * Ainv in row-major format 1232 * tau has length m 1233 * worksize must be >= max(1,n) 1234 */ 1235 static PetscErrorCode PetscDTPseudoInverseQR(PetscInt m,PetscInt mstride,PetscInt n,PetscReal *A_in,PetscReal *Ainv_out,PetscScalar *tau,PetscInt worksize,PetscScalar *work) 1236 { 1237 PetscErrorCode ierr; 1238 PetscBLASInt M,N,K,lda,ldb,ldwork,info; 1239 PetscScalar *A,*Ainv,*R,*Q,Alpha; 1240 1241 PetscFunctionBegin; 1242 #if defined(PETSC_USE_COMPLEX) 1243 { 1244 PetscInt i,j; 1245 ierr = PetscMalloc2(m*n,&A,m*n,&Ainv);CHKERRQ(ierr); 1246 for (j=0; j<n; j++) { 1247 for (i=0; i<m; i++) A[i+m*j] = A_in[i+mstride*j]; 1248 } 1249 mstride = m; 1250 } 1251 #else 1252 A = A_in; 1253 Ainv = Ainv_out; 1254 #endif 1255 1256 ierr = PetscBLASIntCast(m,&M);CHKERRQ(ierr); 1257 ierr = PetscBLASIntCast(n,&N);CHKERRQ(ierr); 1258 ierr = PetscBLASIntCast(mstride,&lda);CHKERRQ(ierr); 1259 ierr = PetscBLASIntCast(worksize,&ldwork);CHKERRQ(ierr); 1260 ierr = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr); 1261 PetscStackCallBLAS("LAPACKgeqrf",LAPACKgeqrf_(&M,&N,A,&lda,tau,work,&ldwork,&info)); 1262 ierr = PetscFPTrapPop();CHKERRQ(ierr); 1263 if (info) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"xGEQRF error"); 1264 R = A; /* Upper triangular part of A now contains R, the rest contains the elementary reflectors */ 1265 1266 /* Extract an explicit representation of Q */ 1267 Q = Ainv; 1268 ierr = PetscMemcpy(Q,A,mstride*n*sizeof(PetscScalar));CHKERRQ(ierr); 1269 K = N; /* full rank */ 1270 PetscStackCallBLAS("LAPACKorgqr",LAPACKorgqr_(&M,&N,&K,Q,&lda,tau,work,&ldwork,&info)); 1271 if (info) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"xORGQR/xUNGQR error"); 1272 1273 /* Compute A^{-T} = (R^{-1} Q^T)^T = Q R^{-T} */ 1274 Alpha = 1.0; 1275 ldb = lda; 1276 PetscStackCallBLAS("BLAStrsm",BLAStrsm_("Right","Upper","ConjugateTranspose","NotUnitTriangular",&M,&N,&Alpha,R,&lda,Q,&ldb)); 1277 /* Ainv is Q, overwritten with inverse */ 1278 1279 #if defined(PETSC_USE_COMPLEX) 1280 { 1281 PetscInt i; 1282 for (i=0; i<m*n; i++) Ainv_out[i] = PetscRealPart(Ainv[i]); 1283 ierr = PetscFree2(A,Ainv);CHKERRQ(ierr); 1284 } 1285 #endif 1286 PetscFunctionReturn(0); 1287 } 1288 1289 /* Computes integral of L_p' over intervals {(x0,x1),(x1,x2),...} */ 1290 static PetscErrorCode PetscDTLegendreIntegrate(PetscInt ninterval,const PetscReal *x,PetscInt ndegree,const PetscInt *degrees,PetscBool Transpose,PetscReal *B) 1291 { 1292 PetscErrorCode ierr; 1293 PetscReal *Bv; 1294 PetscInt i,j; 1295 1296 PetscFunctionBegin; 1297 ierr = PetscMalloc1((ninterval+1)*ndegree,&Bv);CHKERRQ(ierr); 1298 /* Point evaluation of L_p on all the source vertices */ 1299 ierr = PetscDTLegendreEval(ninterval+1,x,ndegree,degrees,Bv,NULL,NULL);CHKERRQ(ierr); 1300 /* Integral over each interval: \int_a^b L_p' = L_p(b)-L_p(a) */ 1301 for (i=0; i<ninterval; i++) { 1302 for (j=0; j<ndegree; j++) { 1303 if (Transpose) B[i+ninterval*j] = Bv[(i+1)*ndegree+j] - Bv[i*ndegree+j]; 1304 else B[i*ndegree+j] = Bv[(i+1)*ndegree+j] - Bv[i*ndegree+j]; 1305 } 1306 } 1307 ierr = PetscFree(Bv);CHKERRQ(ierr); 1308 PetscFunctionReturn(0); 1309 } 1310 1311 /*@ 1312 PetscDTReconstructPoly - create matrix representing polynomial reconstruction using cell intervals and evaluation at target intervals 1313 1314 Not Collective 1315 1316 Input Arguments: 1317 + degree - degree of reconstruction polynomial 1318 . nsource - number of source intervals 1319 . sourcex - sorted coordinates of source cell boundaries (length nsource+1) 1320 . ntarget - number of target intervals 1321 - targetx - sorted coordinates of target cell boundaries (length ntarget+1) 1322 1323 Output Arguments: 1324 . R - reconstruction matrix, utarget = sum_s R[t*nsource+s] * usource[s] 1325 1326 Level: advanced 1327 1328 .seealso: PetscDTLegendreEval() 1329 @*/ 1330 PetscErrorCode PetscDTReconstructPoly(PetscInt degree,PetscInt nsource,const PetscReal *sourcex,PetscInt ntarget,const PetscReal *targetx,PetscReal *R) 1331 { 1332 PetscErrorCode ierr; 1333 PetscInt i,j,k,*bdegrees,worksize; 1334 PetscReal xmin,xmax,center,hscale,*sourcey,*targety,*Bsource,*Bsinv,*Btarget; 1335 PetscScalar *tau,*work; 1336 1337 PetscFunctionBegin; 1338 PetscValidRealPointer(sourcex,3); 1339 PetscValidRealPointer(targetx,5); 1340 PetscValidRealPointer(R,6); 1341 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); 1342 #if defined(PETSC_USE_DEBUG) 1343 for (i=0; i<nsource; i++) { 1344 if (sourcex[i] >= sourcex[i+1]) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_CORRUPT,"Source interval %D has negative orientation (%g,%g)",i,(double)sourcex[i],(double)sourcex[i+1]); 1345 } 1346 for (i=0; i<ntarget; i++) { 1347 if (targetx[i] >= targetx[i+1]) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_CORRUPT,"Target interval %D has negative orientation (%g,%g)",i,(double)targetx[i],(double)targetx[i+1]); 1348 } 1349 #endif 1350 xmin = PetscMin(sourcex[0],targetx[0]); 1351 xmax = PetscMax(sourcex[nsource],targetx[ntarget]); 1352 center = (xmin + xmax)/2; 1353 hscale = (xmax - xmin)/2; 1354 worksize = nsource; 1355 ierr = PetscMalloc4(degree+1,&bdegrees,nsource+1,&sourcey,nsource*(degree+1),&Bsource,worksize,&work);CHKERRQ(ierr); 1356 ierr = PetscMalloc4(nsource,&tau,nsource*(degree+1),&Bsinv,ntarget+1,&targety,ntarget*(degree+1),&Btarget);CHKERRQ(ierr); 1357 for (i=0; i<=nsource; i++) sourcey[i] = (sourcex[i]-center)/hscale; 1358 for (i=0; i<=degree; i++) bdegrees[i] = i+1; 1359 ierr = PetscDTLegendreIntegrate(nsource,sourcey,degree+1,bdegrees,PETSC_TRUE,Bsource);CHKERRQ(ierr); 1360 ierr = PetscDTPseudoInverseQR(nsource,nsource,degree+1,Bsource,Bsinv,tau,nsource,work);CHKERRQ(ierr); 1361 for (i=0; i<=ntarget; i++) targety[i] = (targetx[i]-center)/hscale; 1362 ierr = PetscDTLegendreIntegrate(ntarget,targety,degree+1,bdegrees,PETSC_FALSE,Btarget);CHKERRQ(ierr); 1363 for (i=0; i<ntarget; i++) { 1364 PetscReal rowsum = 0; 1365 for (j=0; j<nsource; j++) { 1366 PetscReal sum = 0; 1367 for (k=0; k<degree+1; k++) { 1368 sum += Btarget[i*(degree+1)+k] * Bsinv[k*nsource+j]; 1369 } 1370 R[i*nsource+j] = sum; 1371 rowsum += sum; 1372 } 1373 for (j=0; j<nsource; j++) R[i*nsource+j] /= rowsum; /* normalize each row */ 1374 } 1375 ierr = PetscFree4(bdegrees,sourcey,Bsource,work);CHKERRQ(ierr); 1376 ierr = PetscFree4(tau,Bsinv,targety,Btarget);CHKERRQ(ierr); 1377 PetscFunctionReturn(0); 1378 } 1379 1380 /*@C 1381 PetscGaussLobattoLegendreIntegrate - Compute the L2 integral of a function on the GLL points 1382 1383 Not Collective 1384 1385 Input Parameter: 1386 + n - the number of GLL nodes 1387 . nodes - the GLL nodes 1388 . weights - the GLL weights 1389 . f - the function values at the nodes 1390 1391 Output Parameter: 1392 . in - the value of the integral 1393 1394 Level: beginner 1395 1396 .seealso: PetscDTGaussLobattoLegendreQuadrature() 1397 1398 @*/ 1399 PetscErrorCode PetscGaussLobattoLegendreIntegrate(PetscInt n,PetscReal *nodes,PetscReal *weights,const PetscReal *f,PetscReal *in) 1400 { 1401 PetscInt i; 1402 1403 PetscFunctionBegin; 1404 *in = 0.; 1405 for (i=0; i<n; i++) { 1406 *in += f[i]*f[i]*weights[i]; 1407 } 1408 PetscFunctionReturn(0); 1409 } 1410 1411 /*@C 1412 PetscGaussLobattoLegendreElementLaplacianCreate - computes the Laplacian for a single 1d GLL element 1413 1414 Not Collective 1415 1416 Input Parameter: 1417 + n - the number of GLL nodes 1418 . nodes - the GLL nodes 1419 . weights - the GLL weights 1420 1421 Output Parameter: 1422 . A - the stiffness element 1423 1424 Level: beginner 1425 1426 Notes: 1427 Destroy this with PetscGaussLobattoLegendreElementLaplacianDestroy() 1428 1429 You can access entries in this array with AA[i][j] but in memory it is stored in contiguous memory, row oriented (the array is symmetric) 1430 1431 .seealso: PetscDTGaussLobattoLegendreQuadrature(), PetscGaussLobattoLegendreElementLaplacianDestroy() 1432 1433 @*/ 1434 PetscErrorCode PetscGaussLobattoLegendreElementLaplacianCreate(PetscInt n,PetscReal *nodes,PetscReal *weights,PetscReal ***AA) 1435 { 1436 PetscReal **A; 1437 PetscErrorCode ierr; 1438 const PetscReal *gllnodes = nodes; 1439 const PetscInt p = n-1; 1440 PetscReal z0,z1,z2 = -1,x,Lpj,Lpr; 1441 PetscInt i,j,nn,r; 1442 1443 PetscFunctionBegin; 1444 ierr = PetscMalloc1(n,&A);CHKERRQ(ierr); 1445 ierr = PetscMalloc1(n*n,&A[0]);CHKERRQ(ierr); 1446 for (i=1; i<n; i++) A[i] = A[i-1]+n; 1447 1448 for (j=1; j<p; j++) { 1449 x = gllnodes[j]; 1450 z0 = 1.; 1451 z1 = x; 1452 for (nn=1; nn<p; nn++) { 1453 z2 = x*z1*(2.*((PetscReal)nn)+1.)/(((PetscReal)nn)+1.)-z0*(((PetscReal)nn)/(((PetscReal)nn)+1.)); 1454 z0 = z1; 1455 z1 = z2; 1456 } 1457 Lpj=z2; 1458 for (r=1; r<p; r++) { 1459 if (r == j) { 1460 A[j][j]=2./(3.*(1.-gllnodes[j]*gllnodes[j])*Lpj*Lpj); 1461 } else { 1462 x = gllnodes[r]; 1463 z0 = 1.; 1464 z1 = x; 1465 for (nn=1; nn<p; nn++) { 1466 z2 = x*z1*(2.*((PetscReal)nn)+1.)/(((PetscReal)nn)+1.)-z0*(((PetscReal)nn)/(((PetscReal)nn)+1.)); 1467 z0 = z1; 1468 z1 = z2; 1469 } 1470 Lpr = z2; 1471 A[r][j] = 4./(((PetscReal)p)*(((PetscReal)p)+1.)*Lpj*Lpr*(gllnodes[j]-gllnodes[r])*(gllnodes[j]-gllnodes[r])); 1472 } 1473 } 1474 } 1475 for (j=1; j<p+1; j++) { 1476 x = gllnodes[j]; 1477 z0 = 1.; 1478 z1 = x; 1479 for (nn=1; nn<p; nn++) { 1480 z2 = x*z1*(2.*((PetscReal)nn)+1.)/(((PetscReal)nn)+1.)-z0*(((PetscReal)nn)/(((PetscReal)nn)+1.)); 1481 z0 = z1; 1482 z1 = z2; 1483 } 1484 Lpj = z2; 1485 A[j][0] = 4.*PetscPowRealInt(-1.,p)/(((PetscReal)p)*(((PetscReal)p)+1.)*Lpj*(1.+gllnodes[j])*(1.+gllnodes[j])); 1486 A[0][j] = A[j][0]; 1487 } 1488 for (j=0; j<p; j++) { 1489 x = gllnodes[j]; 1490 z0 = 1.; 1491 z1 = x; 1492 for (nn=1; nn<p; nn++) { 1493 z2 = x*z1*(2.*((PetscReal)nn)+1.)/(((PetscReal)nn)+1.)-z0*(((PetscReal)nn)/(((PetscReal)nn)+1.)); 1494 z0 = z1; 1495 z1 = z2; 1496 } 1497 Lpj=z2; 1498 1499 A[p][j] = 4./(((PetscReal)p)*(((PetscReal)p)+1.)*Lpj*(1.-gllnodes[j])*(1.-gllnodes[j])); 1500 A[j][p] = A[p][j]; 1501 } 1502 A[0][0]=0.5+(((PetscReal)p)*(((PetscReal)p)+1.)-2.)/6.; 1503 A[p][p]=A[0][0]; 1504 *AA = A; 1505 PetscFunctionReturn(0); 1506 } 1507 1508 /*@C 1509 PetscGaussLobattoLegendreElementLaplacianDestroy - frees the Laplacian for a single 1d GLL element 1510 1511 Not Collective 1512 1513 Input Parameter: 1514 + n - the number of GLL nodes 1515 . nodes - the GLL nodes 1516 . weights - the GLL weightss 1517 - A - the stiffness element 1518 1519 Level: beginner 1520 1521 .seealso: PetscDTGaussLobattoLegendreQuadrature(), PetscGaussLobattoLegendreElementLaplacianCreate() 1522 1523 @*/ 1524 PetscErrorCode PetscGaussLobattoLegendreElementLaplacianDestroy(PetscInt n,PetscReal *nodes,PetscReal *weights,PetscReal ***AA) 1525 { 1526 PetscErrorCode ierr; 1527 1528 PetscFunctionBegin; 1529 ierr = PetscFree((*AA)[0]);CHKERRQ(ierr); 1530 ierr = PetscFree(*AA);CHKERRQ(ierr); 1531 *AA = NULL; 1532 PetscFunctionReturn(0); 1533 } 1534 1535 /*@C 1536 PetscGaussLobattoLegendreElementGradientCreate - computes the gradient for a single 1d GLL element 1537 1538 Not Collective 1539 1540 Input Parameter: 1541 + n - the number of GLL nodes 1542 . nodes - the GLL nodes 1543 . weights - the GLL weights 1544 1545 Output Parameter: 1546 . AA - the stiffness element 1547 - AAT - the transpose of AA (pass in NULL if you do not need this array) 1548 1549 Level: beginner 1550 1551 Notes: 1552 Destroy this with PetscGaussLobattoLegendreElementGradientDestroy() 1553 1554 You can access entries in these arrays with AA[i][j] but in memory it is stored in contiguous memory, row oriented 1555 1556 .seealso: PetscDTGaussLobattoLegendreQuadrature(), PetscGaussLobattoLegendreElementLaplacianDestroy() 1557 1558 @*/ 1559 PetscErrorCode PetscGaussLobattoLegendreElementGradientCreate(PetscInt n,PetscReal *nodes,PetscReal *weights,PetscReal ***AA,PetscReal ***AAT) 1560 { 1561 PetscReal **A, **AT = NULL; 1562 PetscErrorCode ierr; 1563 const PetscReal *gllnodes = nodes; 1564 const PetscInt p = n-1; 1565 PetscReal q,qp,Li, Lj,d0; 1566 PetscInt i,j; 1567 1568 PetscFunctionBegin; 1569 ierr = PetscMalloc1(n,&A);CHKERRQ(ierr); 1570 ierr = PetscMalloc1(n*n,&A[0]);CHKERRQ(ierr); 1571 for (i=1; i<n; i++) A[i] = A[i-1]+n; 1572 1573 if (AAT) { 1574 ierr = PetscMalloc1(n,&AT);CHKERRQ(ierr); 1575 ierr = PetscMalloc1(n*n,&AT[0]);CHKERRQ(ierr); 1576 for (i=1; i<n; i++) AT[i] = AT[i-1]+n; 1577 } 1578 1579 if (n==1) {A[0][0] = 0.;} 1580 d0 = (PetscReal)p*((PetscReal)p+1.)/4.; 1581 for (i=0; i<n; i++) { 1582 for (j=0; j<n; j++) { 1583 A[i][j] = 0.; 1584 qAndLEvaluation(p,gllnodes[i],&q,&qp,&Li); 1585 qAndLEvaluation(p,gllnodes[j],&q,&qp,&Lj); 1586 if (i!=j) A[i][j] = Li/(Lj*(gllnodes[i]-gllnodes[j])); 1587 if ((j==i) && (i==0)) A[i][j] = -d0; 1588 if (j==i && i==p) A[i][j] = d0; 1589 if (AT) AT[j][i] = A[i][j]; 1590 } 1591 } 1592 if (AAT) *AAT = AT; 1593 *AA = A; 1594 PetscFunctionReturn(0); 1595 } 1596 1597 /*@C 1598 PetscGaussLobattoLegendreElementGradientDestroy - frees the gradient for a single 1d GLL element obtained with PetscGaussLobattoLegendreElementGradientCreate() 1599 1600 Not Collective 1601 1602 Input Parameter: 1603 + n - the number of GLL nodes 1604 . nodes - the GLL nodes 1605 . weights - the GLL weights 1606 . AA - the stiffness element 1607 - AAT - the transpose of the element 1608 1609 Level: beginner 1610 1611 .seealso: PetscDTGaussLobattoLegendreQuadrature(), PetscGaussLobattoLegendreElementLaplacianCreate(), PetscGaussLobattoLegendreElementAdvectionCreate() 1612 1613 @*/ 1614 PetscErrorCode PetscGaussLobattoLegendreElementGradientDestroy(PetscInt n,PetscReal *nodes,PetscReal *weights,PetscReal ***AA,PetscReal ***AAT) 1615 { 1616 PetscErrorCode ierr; 1617 1618 PetscFunctionBegin; 1619 ierr = PetscFree((*AA)[0]);CHKERRQ(ierr); 1620 ierr = PetscFree(*AA);CHKERRQ(ierr); 1621 *AA = NULL; 1622 if (*AAT) { 1623 ierr = PetscFree((*AAT)[0]);CHKERRQ(ierr); 1624 ierr = PetscFree(*AAT);CHKERRQ(ierr); 1625 *AAT = NULL; 1626 } 1627 PetscFunctionReturn(0); 1628 } 1629 1630 /*@C 1631 PetscGaussLobattoLegendreElementAdvectionCreate - computes the advection operator for a single 1d GLL element 1632 1633 Not Collective 1634 1635 Input Parameter: 1636 + n - the number of GLL nodes 1637 . nodes - the GLL nodes 1638 . weights - the GLL weightss 1639 1640 Output Parameter: 1641 . AA - the stiffness element 1642 1643 Level: beginner 1644 1645 Notes: 1646 Destroy this with PetscGaussLobattoLegendreElementAdvectionDestroy() 1647 1648 This is the same as the Gradient operator multiplied by the diagonal mass matrix 1649 1650 You can access entries in this array with AA[i][j] but in memory it is stored in contiguous memory, row oriented 1651 1652 .seealso: PetscDTGaussLobattoLegendreQuadrature(), PetscGaussLobattoLegendreElementLaplacianCreate(), PetscGaussLobattoLegendreElementAdvectionDestroy() 1653 1654 @*/ 1655 PetscErrorCode PetscGaussLobattoLegendreElementAdvectionCreate(PetscInt n,PetscReal *nodes,PetscReal *weights,PetscReal ***AA) 1656 { 1657 PetscReal **D; 1658 PetscErrorCode ierr; 1659 const PetscReal *gllweights = weights; 1660 const PetscInt glln = n; 1661 PetscInt i,j; 1662 1663 PetscFunctionBegin; 1664 ierr = PetscGaussLobattoLegendreElementGradientCreate(n,nodes,weights,&D,NULL);CHKERRQ(ierr); 1665 for (i=0; i<glln; i++){ 1666 for (j=0; j<glln; j++) { 1667 D[i][j] = gllweights[i]*D[i][j]; 1668 } 1669 } 1670 *AA = D; 1671 PetscFunctionReturn(0); 1672 } 1673 1674 /*@C 1675 PetscGaussLobattoLegendreElementAdvectionDestroy - frees the advection stiffness for a single 1d GLL element 1676 1677 Not Collective 1678 1679 Input Parameter: 1680 + n - the number of GLL nodes 1681 . nodes - the GLL nodes 1682 . weights - the GLL weights 1683 - A - advection 1684 1685 Level: beginner 1686 1687 .seealso: PetscDTGaussLobattoLegendreQuadrature(), PetscGaussLobattoLegendreElementAdvectionCreate() 1688 1689 @*/ 1690 PetscErrorCode PetscGaussLobattoLegendreElementAdvectionDestroy(PetscInt n,PetscReal *nodes,PetscReal *weights,PetscReal ***AA) 1691 { 1692 PetscErrorCode ierr; 1693 1694 PetscFunctionBegin; 1695 ierr = PetscFree((*AA)[0]);CHKERRQ(ierr); 1696 ierr = PetscFree(*AA);CHKERRQ(ierr); 1697 *AA = NULL; 1698 PetscFunctionReturn(0); 1699 } 1700 1701 PetscErrorCode PetscGaussLobattoLegendreElementMassCreate(PetscInt n,PetscReal *nodes,PetscReal *weights,PetscReal ***AA) 1702 { 1703 PetscReal **A; 1704 PetscErrorCode ierr; 1705 const PetscReal *gllweights = weights; 1706 const PetscInt glln = n; 1707 PetscInt i,j; 1708 1709 PetscFunctionBegin; 1710 ierr = PetscMalloc1(glln,&A);CHKERRQ(ierr); 1711 ierr = PetscMalloc1(glln*glln,&A[0]);CHKERRQ(ierr); 1712 for (i=1; i<glln; i++) A[i] = A[i-1]+glln; 1713 if (glln==1) {A[0][0] = 0.;} 1714 for (i=0; i<glln; i++) { 1715 for (j=0; j<glln; j++) { 1716 A[i][j] = 0.; 1717 if (j==i) A[i][j] = gllweights[i]; 1718 } 1719 } 1720 *AA = A; 1721 PetscFunctionReturn(0); 1722 } 1723 1724 PetscErrorCode PetscGaussLobattoLegendreElementMassDestroy(PetscInt n,PetscReal *nodes,PetscReal *weights,PetscReal ***AA) 1725 { 1726 PetscErrorCode ierr; 1727 1728 PetscFunctionBegin; 1729 ierr = PetscFree((*AA)[0]);CHKERRQ(ierr); 1730 ierr = PetscFree(*AA);CHKERRQ(ierr); 1731 *AA = NULL; 1732 PetscFunctionReturn(0); 1733 } 1734 1735