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 .keywords: PetscQuadrature, quadrature, create 39 .seealso: PetscQuadratureDestroy(), PetscQuadratureGetData() 40 @*/ 41 PetscErrorCode PetscQuadratureCreate(MPI_Comm comm, PetscQuadrature *q) 42 { 43 PetscErrorCode ierr; 44 45 PetscFunctionBegin; 46 PetscValidPointer(q, 2); 47 ierr = PetscSysInitializePackage();CHKERRQ(ierr); 48 ierr = PetscHeaderCreate(*q,PETSC_OBJECT_CLASSID,"PetscQuadrature","Quadrature","DT",comm,PetscQuadratureDestroy,PetscQuadratureView);CHKERRQ(ierr); 49 (*q)->dim = -1; 50 (*q)->Nc = 1; 51 (*q)->order = -1; 52 (*q)->numPoints = 0; 53 (*q)->points = NULL; 54 (*q)->weights = NULL; 55 PetscFunctionReturn(0); 56 } 57 58 /*@ 59 PetscQuadratureDuplicate - Create a deep copy of the PetscQuadrature object 60 61 Collective on PetscQuadrature 62 63 Input Parameter: 64 . q - The PetscQuadrature object 65 66 Output Parameter: 67 . r - The new PetscQuadrature object 68 69 Level: beginner 70 71 .keywords: PetscQuadrature, quadrature, clone 72 .seealso: PetscQuadratureCreate(), PetscQuadratureDestroy(), PetscQuadratureGetData() 73 @*/ 74 PetscErrorCode PetscQuadratureDuplicate(PetscQuadrature q, PetscQuadrature *r) 75 { 76 PetscInt order, dim, Nc, Nq; 77 const PetscReal *points, *weights; 78 PetscReal *p, *w; 79 PetscErrorCode ierr; 80 81 PetscFunctionBegin; 82 PetscValidPointer(q, 2); 83 ierr = PetscQuadratureCreate(PetscObjectComm((PetscObject) q), r);CHKERRQ(ierr); 84 ierr = PetscQuadratureGetOrder(q, &order);CHKERRQ(ierr); 85 ierr = PetscQuadratureSetOrder(*r, order);CHKERRQ(ierr); 86 ierr = PetscQuadratureGetData(q, &dim, &Nc, &Nq, &points, &weights);CHKERRQ(ierr); 87 ierr = PetscMalloc1(Nq*dim, &p);CHKERRQ(ierr); 88 ierr = PetscMalloc1(Nq*Nc, &w);CHKERRQ(ierr); 89 ierr = PetscMemcpy(p, points, Nq*dim * sizeof(PetscReal));CHKERRQ(ierr); 90 ierr = PetscMemcpy(w, weights, Nc * Nq * sizeof(PetscReal));CHKERRQ(ierr); 91 ierr = PetscQuadratureSetData(*r, dim, Nc, Nq, p, w);CHKERRQ(ierr); 92 PetscFunctionReturn(0); 93 } 94 95 /*@ 96 PetscQuadratureDestroy - Destroys a PetscQuadrature object 97 98 Collective on PetscQuadrature 99 100 Input Parameter: 101 . q - The PetscQuadrature object 102 103 Level: beginner 104 105 .keywords: PetscQuadrature, quadrature, destroy 106 .seealso: PetscQuadratureCreate(), PetscQuadratureGetData() 107 @*/ 108 PetscErrorCode PetscQuadratureDestroy(PetscQuadrature *q) 109 { 110 PetscErrorCode ierr; 111 112 PetscFunctionBegin; 113 if (!*q) PetscFunctionReturn(0); 114 PetscValidHeaderSpecific((*q),PETSC_OBJECT_CLASSID,1); 115 if (--((PetscObject)(*q))->refct > 0) { 116 *q = NULL; 117 PetscFunctionReturn(0); 118 } 119 ierr = PetscFree((*q)->points);CHKERRQ(ierr); 120 ierr = PetscFree((*q)->weights);CHKERRQ(ierr); 121 ierr = PetscHeaderDestroy(q);CHKERRQ(ierr); 122 PetscFunctionReturn(0); 123 } 124 125 /*@ 126 PetscQuadratureGetOrder - Return the order of the method 127 128 Not collective 129 130 Input Parameter: 131 . q - The PetscQuadrature object 132 133 Output Parameter: 134 . order - The order of the quadrature, i.e. the highest degree polynomial that is exactly integrated 135 136 Level: intermediate 137 138 .seealso: PetscQuadratureSetOrder(), PetscQuadratureGetData(), PetscQuadratureSetData() 139 @*/ 140 PetscErrorCode PetscQuadratureGetOrder(PetscQuadrature q, PetscInt *order) 141 { 142 PetscFunctionBegin; 143 PetscValidHeaderSpecific(q, PETSC_OBJECT_CLASSID, 1); 144 PetscValidPointer(order, 2); 145 *order = q->order; 146 PetscFunctionReturn(0); 147 } 148 149 /*@ 150 PetscQuadratureSetOrder - Return the order of the method 151 152 Not collective 153 154 Input Parameters: 155 + q - The PetscQuadrature object 156 - order - The order of the quadrature, i.e. the highest degree polynomial that is exactly integrated 157 158 Level: intermediate 159 160 .seealso: PetscQuadratureGetOrder(), PetscQuadratureGetData(), PetscQuadratureSetData() 161 @*/ 162 PetscErrorCode PetscQuadratureSetOrder(PetscQuadrature q, PetscInt order) 163 { 164 PetscFunctionBegin; 165 PetscValidHeaderSpecific(q, PETSC_OBJECT_CLASSID, 1); 166 q->order = order; 167 PetscFunctionReturn(0); 168 } 169 170 /*@ 171 PetscQuadratureGetNumComponents - Return the number of components for functions to be integrated 172 173 Not collective 174 175 Input Parameter: 176 . q - The PetscQuadrature object 177 178 Output Parameter: 179 . Nc - The number of components 180 181 Note: We are performing an integral int f(x) . w(x) dx, where both f and w (the weight) have Nc components. 182 183 Level: intermediate 184 185 .seealso: PetscQuadratureSetNumComponents(), PetscQuadratureGetData(), PetscQuadratureSetData() 186 @*/ 187 PetscErrorCode PetscQuadratureGetNumComponents(PetscQuadrature q, PetscInt *Nc) 188 { 189 PetscFunctionBegin; 190 PetscValidHeaderSpecific(q, PETSC_OBJECT_CLASSID, 1); 191 PetscValidPointer(Nc, 2); 192 *Nc = q->Nc; 193 PetscFunctionReturn(0); 194 } 195 196 /*@ 197 PetscQuadratureSetNumComponents - Return the number of components for functions to be integrated 198 199 Not collective 200 201 Input Parameters: 202 + q - The PetscQuadrature object 203 - Nc - The number of components 204 205 Note: We are performing an integral int f(x) . w(x) dx, where both f and w (the weight) have Nc components. 206 207 Level: intermediate 208 209 .seealso: PetscQuadratureGetNumComponents(), PetscQuadratureGetData(), PetscQuadratureSetData() 210 @*/ 211 PetscErrorCode PetscQuadratureSetNumComponents(PetscQuadrature q, PetscInt Nc) 212 { 213 PetscFunctionBegin; 214 PetscValidHeaderSpecific(q, PETSC_OBJECT_CLASSID, 1); 215 q->Nc = Nc; 216 PetscFunctionReturn(0); 217 } 218 219 /*@C 220 PetscQuadratureGetData - Returns the data defining the quadrature 221 222 Not collective 223 224 Input Parameter: 225 . q - The PetscQuadrature object 226 227 Output Parameters: 228 + dim - The spatial dimension 229 . Nc - The number of components 230 . npoints - The number of quadrature points 231 . points - The coordinates of each quadrature point 232 - weights - The weight of each quadrature point 233 234 Level: intermediate 235 236 Fortran Notes: 237 From Fortran you must call PetscQuadratureRestoreData() when you are done with the data 238 239 .keywords: PetscQuadrature, quadrature 240 .seealso: PetscQuadratureCreate(), PetscQuadratureSetData() 241 @*/ 242 PetscErrorCode PetscQuadratureGetData(PetscQuadrature q, PetscInt *dim, PetscInt *Nc, PetscInt *npoints, const PetscReal *points[], const PetscReal *weights[]) 243 { 244 PetscFunctionBegin; 245 PetscValidHeaderSpecific(q, PETSC_OBJECT_CLASSID, 1); 246 if (dim) { 247 PetscValidPointer(dim, 2); 248 *dim = q->dim; 249 } 250 if (Nc) { 251 PetscValidPointer(Nc, 3); 252 *Nc = q->Nc; 253 } 254 if (npoints) { 255 PetscValidPointer(npoints, 4); 256 *npoints = q->numPoints; 257 } 258 if (points) { 259 PetscValidPointer(points, 5); 260 *points = q->points; 261 } 262 if (weights) { 263 PetscValidPointer(weights, 6); 264 *weights = q->weights; 265 } 266 PetscFunctionReturn(0); 267 } 268 269 /*@C 270 PetscQuadratureSetData - Sets the data defining the quadrature 271 272 Not collective 273 274 Input Parameters: 275 + q - The PetscQuadrature object 276 . dim - The spatial dimension 277 . Nc - The number of components 278 . npoints - The number of quadrature points 279 . points - The coordinates of each quadrature point 280 - weights - The weight of each quadrature point 281 282 Note: This routine owns the references to points and weights, so they must be allocated using PetscMalloc() and the user should not free them. 283 284 Level: intermediate 285 286 .keywords: PetscQuadrature, quadrature 287 .seealso: PetscQuadratureCreate(), PetscQuadratureGetData() 288 @*/ 289 PetscErrorCode PetscQuadratureSetData(PetscQuadrature q, PetscInt dim, PetscInt Nc, PetscInt npoints, const PetscReal points[], const PetscReal weights[]) 290 { 291 PetscFunctionBegin; 292 PetscValidHeaderSpecific(q, PETSC_OBJECT_CLASSID, 1); 293 if (dim >= 0) q->dim = dim; 294 if (Nc >= 0) q->Nc = Nc; 295 if (npoints >= 0) q->numPoints = npoints; 296 if (points) { 297 PetscValidPointer(points, 4); 298 q->points = points; 299 } 300 if (weights) { 301 PetscValidPointer(weights, 5); 302 q->weights = weights; 303 } 304 PetscFunctionReturn(0); 305 } 306 307 static PetscErrorCode PetscQuadratureView_Ascii(PetscQuadrature quad, PetscViewer v) 308 { 309 PetscInt q, d, c; 310 PetscViewerFormat format; 311 PetscErrorCode ierr; 312 313 PetscFunctionBegin; 314 if (quad->Nc > 1) {ierr = PetscViewerASCIIPrintf(v, "Quadrature on %D points with %D components of order %D\n", quad->numPoints, quad->Nc, quad->order);CHKERRQ(ierr);} 315 else {ierr = PetscViewerASCIIPrintf(v, "Quadrature on %D points of order %D\n", quad->numPoints, quad->order);CHKERRQ(ierr);} 316 ierr = PetscViewerGetFormat(v, &format);CHKERRQ(ierr); 317 if (format != PETSC_VIEWER_ASCII_INFO_DETAIL) PetscFunctionReturn(0); 318 for (q = 0; q < quad->numPoints; ++q) { 319 ierr = PetscViewerASCIIPrintf(v, "(");CHKERRQ(ierr); 320 ierr = PetscViewerASCIIUseTabs(v, PETSC_FALSE);CHKERRQ(ierr); 321 for (d = 0; d < quad->dim; ++d) { 322 if (d) {ierr = PetscViewerASCIIPrintf(v, ", ");CHKERRQ(ierr);} 323 ierr = PetscViewerASCIIPrintf(v, "%+g", (double)quad->points[q*quad->dim+d]);CHKERRQ(ierr); 324 } 325 ierr = PetscViewerASCIIPrintf(v, ") ");CHKERRQ(ierr); 326 if (quad->Nc > 1) {ierr = PetscViewerASCIIPrintf(v, "(");CHKERRQ(ierr);} 327 for (c = 0; c < quad->Nc; ++c) { 328 if (c) {ierr = PetscViewerASCIIPrintf(v, ", ");CHKERRQ(ierr);} 329 ierr = PetscViewerASCIIPrintf(v, "%g", (double)quad->weights[q*quad->Nc+c]);CHKERRQ(ierr); 330 } 331 if (quad->Nc > 1) {ierr = PetscViewerASCIIPrintf(v, ")");CHKERRQ(ierr);} 332 ierr = PetscViewerASCIIPrintf(v, "\n");CHKERRQ(ierr); 333 ierr = PetscViewerASCIIUseTabs(v, PETSC_TRUE);CHKERRQ(ierr); 334 } 335 PetscFunctionReturn(0); 336 } 337 338 /*@C 339 PetscQuadratureView - Views a PetscQuadrature object 340 341 Collective on PetscQuadrature 342 343 Input Parameters: 344 + quad - The PetscQuadrature object 345 - viewer - The PetscViewer object 346 347 Level: beginner 348 349 .keywords: PetscQuadrature, quadrature, view 350 .seealso: PetscQuadratureCreate(), PetscQuadratureGetData() 351 @*/ 352 PetscErrorCode PetscQuadratureView(PetscQuadrature quad, PetscViewer viewer) 353 { 354 PetscBool iascii; 355 PetscErrorCode ierr; 356 357 PetscFunctionBegin; 358 PetscValidHeader(quad, 1); 359 if (viewer) PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 360 if (!viewer) {ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject) quad), &viewer);CHKERRQ(ierr);} 361 ierr = PetscObjectPrintClassNamePrefixType((PetscObject)quad, viewer);CHKERRQ(ierr); 362 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr); 363 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 364 if (iascii) {ierr = PetscQuadratureView_Ascii(quad, viewer);CHKERRQ(ierr);} 365 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 366 PetscFunctionReturn(0); 367 } 368 369 /*@C 370 PetscQuadratureExpandComposite - Return a quadrature over the composite element, which has the original quadrature in each subelement 371 372 Not collective 373 374 Input Parameter: 375 + q - The original PetscQuadrature 376 . numSubelements - The number of subelements the original element is divided into 377 . v0 - An array of the initial points for each subelement 378 - jac - An array of the Jacobian mappings from the reference to each subelement 379 380 Output Parameters: 381 . dim - The dimension 382 383 Note: Together v0 and jac define an affine mapping from the original reference element to each subelement 384 385 Not available from Fortran 386 387 Level: intermediate 388 389 .seealso: PetscFECreate(), PetscSpaceGetDimension(), PetscDualSpaceGetDimension() 390 @*/ 391 PetscErrorCode PetscQuadratureExpandComposite(PetscQuadrature q, PetscInt numSubelements, const PetscReal v0[], const PetscReal jac[], PetscQuadrature *qref) 392 { 393 const PetscReal *points, *weights; 394 PetscReal *pointsRef, *weightsRef; 395 PetscInt dim, Nc, order, npoints, npointsRef, c, p, cp, d, e; 396 PetscErrorCode ierr; 397 398 PetscFunctionBegin; 399 PetscValidHeaderSpecific(q, PETSC_OBJECT_CLASSID, 1); 400 PetscValidPointer(v0, 3); 401 PetscValidPointer(jac, 4); 402 PetscValidPointer(qref, 5); 403 ierr = PetscQuadratureCreate(PETSC_COMM_SELF, qref);CHKERRQ(ierr); 404 ierr = PetscQuadratureGetOrder(q, &order);CHKERRQ(ierr); 405 ierr = PetscQuadratureGetData(q, &dim, &Nc, &npoints, &points, &weights);CHKERRQ(ierr); 406 npointsRef = npoints*numSubelements; 407 ierr = PetscMalloc1(npointsRef*dim,&pointsRef);CHKERRQ(ierr); 408 ierr = PetscMalloc1(npointsRef*Nc, &weightsRef);CHKERRQ(ierr); 409 for (c = 0; c < numSubelements; ++c) { 410 for (p = 0; p < npoints; ++p) { 411 for (d = 0; d < dim; ++d) { 412 pointsRef[(c*npoints + p)*dim+d] = v0[c*dim+d]; 413 for (e = 0; e < dim; ++e) { 414 pointsRef[(c*npoints + p)*dim+d] += jac[(c*dim + d)*dim+e]*(points[p*dim+e] + 1.0); 415 } 416 } 417 /* Could also use detJ here */ 418 for (cp = 0; cp < Nc; ++cp) weightsRef[(c*npoints+p)*Nc+cp] = weights[p*Nc+cp]/numSubelements; 419 } 420 } 421 ierr = PetscQuadratureSetOrder(*qref, order);CHKERRQ(ierr); 422 ierr = PetscQuadratureSetData(*qref, dim, Nc, npointsRef, pointsRef, weightsRef);CHKERRQ(ierr); 423 PetscFunctionReturn(0); 424 } 425 426 /*@ 427 PetscDTLegendreEval - evaluate Legendre polynomial at points 428 429 Not Collective 430 431 Input Arguments: 432 + npoints - number of spatial points to evaluate at 433 . points - array of locations to evaluate at 434 . ndegree - number of basis degrees to evaluate 435 - degrees - sorted array of degrees to evaluate 436 437 Output Arguments: 438 + B - row-oriented basis evaluation matrix B[point*ndegree + degree] (dimension npoints*ndegrees, allocated by caller) (or NULL) 439 . D - row-oriented derivative evaluation matrix (or NULL) 440 - D2 - row-oriented second derivative evaluation matrix (or NULL) 441 442 Level: intermediate 443 444 .seealso: PetscDTGaussQuadrature() 445 @*/ 446 PetscErrorCode PetscDTLegendreEval(PetscInt npoints,const PetscReal *points,PetscInt ndegree,const PetscInt *degrees,PetscReal *B,PetscReal *D,PetscReal *D2) 447 { 448 PetscInt i,maxdegree; 449 450 PetscFunctionBegin; 451 if (!npoints || !ndegree) PetscFunctionReturn(0); 452 maxdegree = degrees[ndegree-1]; 453 for (i=0; i<npoints; i++) { 454 PetscReal pm1,pm2,pd1,pd2,pdd1,pdd2,x; 455 PetscInt j,k; 456 x = points[i]; 457 pm2 = 0; 458 pm1 = 1; 459 pd2 = 0; 460 pd1 = 0; 461 pdd2 = 0; 462 pdd1 = 0; 463 k = 0; 464 if (degrees[k] == 0) { 465 if (B) B[i*ndegree+k] = pm1; 466 if (D) D[i*ndegree+k] = pd1; 467 if (D2) D2[i*ndegree+k] = pdd1; 468 k++; 469 } 470 for (j=1; j<=maxdegree; j++,k++) { 471 PetscReal p,d,dd; 472 p = ((2*j-1)*x*pm1 - (j-1)*pm2)/j; 473 d = pd2 + (2*j-1)*pm1; 474 dd = pdd2 + (2*j-1)*pd1; 475 pm2 = pm1; 476 pm1 = p; 477 pd2 = pd1; 478 pd1 = d; 479 pdd2 = pdd1; 480 pdd1 = dd; 481 if (degrees[k] == j) { 482 if (B) B[i*ndegree+k] = p; 483 if (D) D[i*ndegree+k] = d; 484 if (D2) D2[i*ndegree+k] = dd; 485 } 486 } 487 } 488 PetscFunctionReturn(0); 489 } 490 491 /*@ 492 PetscDTGaussQuadrature - create Gauss quadrature 493 494 Not Collective 495 496 Input Arguments: 497 + npoints - number of points 498 . a - left end of interval (often-1) 499 - b - right end of interval (often +1) 500 501 Output Arguments: 502 + x - quadrature points 503 - w - quadrature weights 504 505 Level: intermediate 506 507 References: 508 . 1. - Golub and Welsch, Calculation of Quadrature Rules, Math. Comp. 23(106), 1969. 509 510 .seealso: PetscDTLegendreEval() 511 @*/ 512 PetscErrorCode PetscDTGaussQuadrature(PetscInt npoints,PetscReal a,PetscReal b,PetscReal *x,PetscReal *w) 513 { 514 PetscErrorCode ierr; 515 PetscInt i; 516 PetscReal *work; 517 PetscScalar *Z; 518 PetscBLASInt N,LDZ,info; 519 520 PetscFunctionBegin; 521 ierr = PetscCitationsRegister(GaussCitation, &GaussCite);CHKERRQ(ierr); 522 /* Set up the Golub-Welsch system */ 523 for (i=0; i<npoints; i++) { 524 x[i] = 0; /* diagonal is 0 */ 525 if (i) w[i-1] = 0.5 / PetscSqrtReal(1 - 1./PetscSqr(2*i)); 526 } 527 ierr = PetscMalloc2(npoints*npoints,&Z,PetscMax(1,2*npoints-2),&work);CHKERRQ(ierr); 528 ierr = PetscBLASIntCast(npoints,&N);CHKERRQ(ierr); 529 LDZ = N; 530 ierr = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr); 531 PetscStackCallBLAS("LAPACKsteqr",LAPACKsteqr_("I",&N,x,w,Z,&LDZ,work,&info)); 532 ierr = PetscFPTrapPop();CHKERRQ(ierr); 533 if (info) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"xSTEQR error"); 534 535 for (i=0; i<(npoints+1)/2; i++) { 536 PetscReal y = 0.5 * (-x[i] + x[npoints-i-1]); /* enforces symmetry */ 537 x[i] = (a+b)/2 - y*(b-a)/2; 538 if (x[i] == -0.0) x[i] = 0.0; 539 x[npoints-i-1] = (a+b)/2 + y*(b-a)/2; 540 541 w[i] = w[npoints-1-i] = 0.5*(b-a)*(PetscSqr(PetscAbsScalar(Z[i*npoints])) + PetscSqr(PetscAbsScalar(Z[(npoints-i-1)*npoints]))); 542 } 543 ierr = PetscFree2(Z,work);CHKERRQ(ierr); 544 PetscFunctionReturn(0); 545 } 546 547 /*@ 548 PetscDTGaussTensorQuadrature - creates a tensor-product Gauss quadrature 549 550 Not Collective 551 552 Input Arguments: 553 + dim - The spatial dimension 554 . Nc - The number of components 555 . npoints - number of points in one dimension 556 . a - left end of interval (often-1) 557 - b - right end of interval (often +1) 558 559 Output Argument: 560 . q - A PetscQuadrature object 561 562 Level: intermediate 563 564 .seealso: PetscDTGaussQuadrature(), PetscDTLegendreEval() 565 @*/ 566 PetscErrorCode PetscDTGaussTensorQuadrature(PetscInt dim, PetscInt Nc, PetscInt npoints, PetscReal a, PetscReal b, PetscQuadrature *q) 567 { 568 PetscInt totpoints = dim > 1 ? dim > 2 ? npoints*PetscSqr(npoints) : PetscSqr(npoints) : npoints, i, j, k, c; 569 PetscReal *x, *w, *xw, *ww; 570 PetscErrorCode ierr; 571 572 PetscFunctionBegin; 573 ierr = PetscMalloc1(totpoints*dim,&x);CHKERRQ(ierr); 574 ierr = PetscMalloc1(totpoints*Nc,&w);CHKERRQ(ierr); 575 /* Set up the Golub-Welsch system */ 576 switch (dim) { 577 case 0: 578 ierr = PetscFree(x);CHKERRQ(ierr); 579 ierr = PetscFree(w);CHKERRQ(ierr); 580 ierr = PetscMalloc1(1, &x);CHKERRQ(ierr); 581 ierr = PetscMalloc1(Nc, &w);CHKERRQ(ierr); 582 x[0] = 0.0; 583 for (c = 0; c < Nc; ++c) w[c] = 1.0; 584 break; 585 case 1: 586 ierr = PetscMalloc1(npoints,&ww);CHKERRQ(ierr); 587 ierr = PetscDTGaussQuadrature(npoints, a, b, x, ww);CHKERRQ(ierr); 588 for (i = 0; i < npoints; ++i) for (c = 0; c < Nc; ++c) w[i*Nc+c] = ww[i]; 589 ierr = PetscFree(ww);CHKERRQ(ierr); 590 break; 591 case 2: 592 ierr = PetscMalloc2(npoints,&xw,npoints,&ww);CHKERRQ(ierr); 593 ierr = PetscDTGaussQuadrature(npoints, a, b, xw, ww);CHKERRQ(ierr); 594 for (i = 0; i < npoints; ++i) { 595 for (j = 0; j < npoints; ++j) { 596 x[(i*npoints+j)*dim+0] = xw[i]; 597 x[(i*npoints+j)*dim+1] = xw[j]; 598 for (c = 0; c < Nc; ++c) w[(i*npoints+j)*Nc+c] = ww[i] * ww[j]; 599 } 600 } 601 ierr = PetscFree2(xw,ww);CHKERRQ(ierr); 602 break; 603 case 3: 604 ierr = PetscMalloc2(npoints,&xw,npoints,&ww);CHKERRQ(ierr); 605 ierr = PetscDTGaussQuadrature(npoints, a, b, xw, ww);CHKERRQ(ierr); 606 for (i = 0; i < npoints; ++i) { 607 for (j = 0; j < npoints; ++j) { 608 for (k = 0; k < npoints; ++k) { 609 x[((i*npoints+j)*npoints+k)*dim+0] = xw[i]; 610 x[((i*npoints+j)*npoints+k)*dim+1] = xw[j]; 611 x[((i*npoints+j)*npoints+k)*dim+2] = xw[k]; 612 for (c = 0; c < Nc; ++c) w[((i*npoints+j)*npoints+k)*Nc+c] = ww[i] * ww[j] * ww[k]; 613 } 614 } 615 } 616 ierr = PetscFree2(xw,ww);CHKERRQ(ierr); 617 break; 618 default: 619 SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct quadrature rule for dimension %d", dim); 620 } 621 ierr = PetscQuadratureCreate(PETSC_COMM_SELF, q);CHKERRQ(ierr); 622 ierr = PetscQuadratureSetOrder(*q, 2*npoints-1);CHKERRQ(ierr); 623 ierr = PetscQuadratureSetData(*q, dim, Nc, totpoints, x, w);CHKERRQ(ierr); 624 ierr = PetscObjectChangeTypeName((PetscObject)*q,"GaussTensor");CHKERRQ(ierr); 625 PetscFunctionReturn(0); 626 } 627 628 /* Evaluates the nth jacobi polynomial with weight parameters a,b at a point x. 629 Recurrence relations implemented from the pseudocode given in Karniadakis and Sherwin, Appendix B */ 630 PETSC_STATIC_INLINE PetscErrorCode PetscDTFactorial_Internal(PetscInt n, PetscReal *factorial) 631 { 632 PetscReal f = 1.0; 633 PetscInt i; 634 635 PetscFunctionBegin; 636 for (i = 1; i < n+1; ++i) f *= i; 637 *factorial = f; 638 PetscFunctionReturn(0); 639 } 640 641 /* Evaluates the nth jacobi polynomial with weight parameters a,b at a point x. 642 Recurrence relations implemented from the pseudocode given in Karniadakis and Sherwin, Appendix B */ 643 PETSC_STATIC_INLINE PetscErrorCode PetscDTComputeJacobi(PetscReal a, PetscReal b, PetscInt n, PetscReal x, PetscReal *P) 644 { 645 PetscReal apb, pn1, pn2; 646 PetscInt k; 647 648 PetscFunctionBegin; 649 if (!n) {*P = 1.0; PetscFunctionReturn(0);} 650 if (n == 1) {*P = 0.5 * (a - b + (a + b + 2.0) * x); PetscFunctionReturn(0);} 651 apb = a + b; 652 pn2 = 1.0; 653 pn1 = 0.5 * (a - b + (apb + 2.0) * x); 654 *P = 0.0; 655 for (k = 2; k < n+1; ++k) { 656 PetscReal a1 = 2.0 * k * (k + apb) * (2.0*k + apb - 2.0); 657 PetscReal a2 = (2.0 * k + apb - 1.0) * (a*a - b*b); 658 PetscReal a3 = (2.0 * k + apb - 2.0) * (2.0 * k + apb - 1.0) * (2.0 * k + apb); 659 PetscReal a4 = 2.0 * (k + a - 1.0) * (k + b - 1.0) * (2.0 * k + apb); 660 661 a2 = a2 / a1; 662 a3 = a3 / a1; 663 a4 = a4 / a1; 664 *P = (a2 + a3 * x) * pn1 - a4 * pn2; 665 pn2 = pn1; 666 pn1 = *P; 667 } 668 PetscFunctionReturn(0); 669 } 670 671 /* Evaluates the first derivative of P_{n}^{a,b} at a point x. */ 672 PETSC_STATIC_INLINE PetscErrorCode PetscDTComputeJacobiDerivative(PetscReal a, PetscReal b, PetscInt n, PetscReal x, PetscReal *P) 673 { 674 PetscReal nP; 675 PetscErrorCode ierr; 676 677 PetscFunctionBegin; 678 if (!n) {*P = 0.0; PetscFunctionReturn(0);} 679 ierr = PetscDTComputeJacobi(a+1, b+1, n-1, x, &nP);CHKERRQ(ierr); 680 *P = 0.5 * (a + b + n + 1) * nP; 681 PetscFunctionReturn(0); 682 } 683 684 /* Maps from [-1,1]^2 to the (-1,1) reference triangle */ 685 PETSC_STATIC_INLINE PetscErrorCode PetscDTMapSquareToTriangle_Internal(PetscReal x, PetscReal y, PetscReal *xi, PetscReal *eta) 686 { 687 PetscFunctionBegin; 688 *xi = 0.5 * (1.0 + x) * (1.0 - y) - 1.0; 689 *eta = y; 690 PetscFunctionReturn(0); 691 } 692 693 /* Maps from [-1,1]^2 to the (-1,1) reference triangle */ 694 PETSC_STATIC_INLINE PetscErrorCode PetscDTMapCubeToTetrahedron_Internal(PetscReal x, PetscReal y, PetscReal z, PetscReal *xi, PetscReal *eta, PetscReal *zeta) 695 { 696 PetscFunctionBegin; 697 *xi = 0.25 * (1.0 + x) * (1.0 - y) * (1.0 - z) - 1.0; 698 *eta = 0.5 * (1.0 + y) * (1.0 - z) - 1.0; 699 *zeta = z; 700 PetscFunctionReturn(0); 701 } 702 703 static PetscErrorCode PetscDTGaussJacobiQuadrature1D_Internal(PetscInt npoints, PetscReal a, PetscReal b, PetscReal *x, PetscReal *w) 704 { 705 PetscInt maxIter = 100; 706 PetscReal eps = 1.0e-8; 707 PetscReal a1, a2, a3, a4, a5, a6; 708 PetscInt k; 709 PetscErrorCode ierr; 710 711 PetscFunctionBegin; 712 713 a1 = PetscPowReal(2.0, a+b+1); 714 #if defined(PETSC_HAVE_TGAMMA) 715 a2 = PetscTGamma(a + npoints + 1); 716 a3 = PetscTGamma(b + npoints + 1); 717 a4 = PetscTGamma(a + b + npoints + 1); 718 #else 719 { 720 PetscInt ia, ib; 721 722 ia = (PetscInt) a; 723 ib = (PetscInt) b; 724 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 */ 725 ierr = PetscDTFactorial_Internal(ia + npoints, &a2);CHKERRQ(ierr); 726 ierr = PetscDTFactorial_Internal(ib + npoints, &a3);CHKERRQ(ierr); 727 ierr = PetscDTFactorial_Internal(ia + ib + npoints, &a4);CHKERRQ(ierr); 728 } else { 729 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"tgamma() - math routine is unavailable."); 730 } 731 } 732 #endif 733 734 ierr = PetscDTFactorial_Internal(npoints, &a5);CHKERRQ(ierr); 735 a6 = a1 * a2 * a3 / a4 / a5; 736 /* Computes the m roots of P_{m}^{a,b} on [-1,1] by Newton's method with Chebyshev points as initial guesses. 737 Algorithm implemented from the pseudocode given by Karniadakis and Sherwin and Python in FIAT */ 738 for (k = 0; k < npoints; ++k) { 739 PetscReal r = -PetscCosReal((2.0*k + 1.0) * PETSC_PI / (2.0 * npoints)), dP; 740 PetscInt j; 741 742 if (k > 0) r = 0.5 * (r + x[k-1]); 743 for (j = 0; j < maxIter; ++j) { 744 PetscReal s = 0.0, delta, f, fp; 745 PetscInt i; 746 747 for (i = 0; i < k; ++i) s = s + 1.0 / (r - x[i]); 748 ierr = PetscDTComputeJacobi(a, b, npoints, r, &f);CHKERRQ(ierr); 749 ierr = PetscDTComputeJacobiDerivative(a, b, npoints, r, &fp);CHKERRQ(ierr); 750 delta = f / (fp - f * s); 751 r = r - delta; 752 if (PetscAbsReal(delta) < eps) break; 753 } 754 x[k] = r; 755 ierr = PetscDTComputeJacobiDerivative(a, b, npoints, x[k], &dP);CHKERRQ(ierr); 756 w[k] = a6 / (1.0 - PetscSqr(x[k])) / PetscSqr(dP); 757 } 758 PetscFunctionReturn(0); 759 } 760 761 /*@ 762 PetscDTGaussJacobiQuadrature - create Gauss-Jacobi quadrature for a simplex 763 764 Not Collective 765 766 Input Arguments: 767 + dim - The simplex dimension 768 . Nc - The number of components 769 . npoints - The number of points in one dimension 770 . a - left end of interval (often-1) 771 - b - right end of interval (often +1) 772 773 Output Argument: 774 . q - A PetscQuadrature object 775 776 Level: intermediate 777 778 References: 779 . 1. - Karniadakis and Sherwin. FIAT 780 781 .seealso: PetscDTGaussTensorQuadrature(), PetscDTGaussQuadrature() 782 @*/ 783 PetscErrorCode PetscDTGaussJacobiQuadrature(PetscInt dim, PetscInt Nc, PetscInt npoints, PetscReal a, PetscReal b, PetscQuadrature *q) 784 { 785 PetscInt totpoints = dim > 1 ? dim > 2 ? npoints*PetscSqr(npoints) : PetscSqr(npoints) : npoints; 786 PetscReal *px, *wx, *py, *wy, *pz, *wz, *x, *w; 787 PetscInt i, j, k, c; 788 PetscErrorCode ierr; 789 790 PetscFunctionBegin; 791 if ((a != -1.0) || (b != 1.0)) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must use default internal right now"); 792 ierr = PetscMalloc1(totpoints*dim, &x);CHKERRQ(ierr); 793 ierr = PetscMalloc1(totpoints*Nc, &w);CHKERRQ(ierr); 794 switch (dim) { 795 case 0: 796 ierr = PetscFree(x);CHKERRQ(ierr); 797 ierr = PetscFree(w);CHKERRQ(ierr); 798 ierr = PetscMalloc1(1, &x);CHKERRQ(ierr); 799 ierr = PetscMalloc1(Nc, &w);CHKERRQ(ierr); 800 x[0] = 0.0; 801 for (c = 0; c < Nc; ++c) w[c] = 1.0; 802 break; 803 case 1: 804 ierr = PetscMalloc1(npoints,&wx);CHKERRQ(ierr); 805 ierr = PetscDTGaussJacobiQuadrature1D_Internal(npoints, 0.0, 0.0, x, wx);CHKERRQ(ierr); 806 for (i = 0; i < npoints; ++i) for (c = 0; c < Nc; ++c) w[i*Nc+c] = wx[i]; 807 ierr = PetscFree(wx);CHKERRQ(ierr); 808 break; 809 case 2: 810 ierr = PetscMalloc4(npoints,&px,npoints,&wx,npoints,&py,npoints,&wy);CHKERRQ(ierr); 811 ierr = PetscDTGaussJacobiQuadrature1D_Internal(npoints, 0.0, 0.0, px, wx);CHKERRQ(ierr); 812 ierr = PetscDTGaussJacobiQuadrature1D_Internal(npoints, 1.0, 0.0, py, wy);CHKERRQ(ierr); 813 for (i = 0; i < npoints; ++i) { 814 for (j = 0; j < npoints; ++j) { 815 ierr = PetscDTMapSquareToTriangle_Internal(px[i], py[j], &x[(i*npoints+j)*2+0], &x[(i*npoints+j)*2+1]);CHKERRQ(ierr); 816 for (c = 0; c < Nc; ++c) w[(i*npoints+j)*Nc+c] = 0.5 * wx[i] * wy[j]; 817 } 818 } 819 ierr = PetscFree4(px,wx,py,wy);CHKERRQ(ierr); 820 break; 821 case 3: 822 ierr = PetscMalloc6(npoints,&px,npoints,&wx,npoints,&py,npoints,&wy,npoints,&pz,npoints,&wz);CHKERRQ(ierr); 823 ierr = PetscDTGaussJacobiQuadrature1D_Internal(npoints, 0.0, 0.0, px, wx);CHKERRQ(ierr); 824 ierr = PetscDTGaussJacobiQuadrature1D_Internal(npoints, 1.0, 0.0, py, wy);CHKERRQ(ierr); 825 ierr = PetscDTGaussJacobiQuadrature1D_Internal(npoints, 2.0, 0.0, pz, wz);CHKERRQ(ierr); 826 for (i = 0; i < npoints; ++i) { 827 for (j = 0; j < npoints; ++j) { 828 for (k = 0; k < npoints; ++k) { 829 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); 830 for (c = 0; c < Nc; ++c) w[((i*npoints+j)*npoints+k)*Nc+c] = 0.125 * wx[i] * wy[j] * wz[k]; 831 } 832 } 833 } 834 ierr = PetscFree6(px,wx,py,wy,pz,wz);CHKERRQ(ierr); 835 break; 836 default: 837 SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct quadrature rule for dimension %d", dim); 838 } 839 ierr = PetscQuadratureCreate(PETSC_COMM_SELF, q);CHKERRQ(ierr); 840 ierr = PetscQuadratureSetOrder(*q, 2*npoints-1);CHKERRQ(ierr); 841 ierr = PetscQuadratureSetData(*q, dim, Nc, totpoints, x, w);CHKERRQ(ierr); 842 ierr = PetscObjectChangeTypeName((PetscObject)*q,"GaussJacobi");CHKERRQ(ierr); 843 PetscFunctionReturn(0); 844 } 845 846 /*@ 847 PetscDTTanhSinhTensorQuadrature - create tanh-sinh quadrature for a tensor product cell 848 849 Not Collective 850 851 Input Arguments: 852 + dim - The cell dimension 853 . level - The number of points in one dimension, 2^l 854 . a - left end of interval (often-1) 855 - b - right end of interval (often +1) 856 857 Output Argument: 858 . q - A PetscQuadrature object 859 860 Level: intermediate 861 862 .seealso: PetscDTGaussTensorQuadrature() 863 @*/ 864 PetscErrorCode PetscDTTanhSinhTensorQuadrature(PetscInt dim, PetscInt level, PetscReal a, PetscReal b, PetscQuadrature *q) 865 { 866 const PetscInt p = 16; /* Digits of precision in the evaluation */ 867 const PetscReal alpha = (b-a)/2.; /* Half-width of the integration interval */ 868 const PetscReal beta = (b+a)/2.; /* Center of the integration interval */ 869 const PetscReal h = PetscPowReal(2.0, -level); /* Step size, length between x_k */ 870 PetscReal xk; /* Quadrature point x_k on reference domain [-1, 1] */ 871 PetscReal wk = 0.5*PETSC_PI; /* Quadrature weight at x_k */ 872 PetscReal *x, *w; 873 PetscInt K, k, npoints; 874 PetscErrorCode ierr; 875 876 PetscFunctionBegin; 877 if (dim > 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Dimension %d not yet implemented", dim); 878 if (!level) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must give a number of significant digits"); 879 /* Find K such that the weights are < 32 digits of precision */ 880 for (K = 1; PetscAbsReal(PetscLog10Real(wk)) < 2*p; ++K) { 881 wk = 0.5*h*PETSC_PI*PetscCoshReal(K*h)/PetscSqr(PetscCoshReal(0.5*PETSC_PI*PetscSinhReal(K*h))); 882 } 883 ierr = PetscQuadratureCreate(PETSC_COMM_SELF, q);CHKERRQ(ierr); 884 ierr = PetscQuadratureSetOrder(*q, 2*K+1);CHKERRQ(ierr); 885 npoints = 2*K-1; 886 ierr = PetscMalloc1(npoints*dim, &x);CHKERRQ(ierr); 887 ierr = PetscMalloc1(npoints, &w);CHKERRQ(ierr); 888 /* Center term */ 889 x[0] = beta; 890 w[0] = 0.5*alpha*PETSC_PI; 891 for (k = 1; k < K; ++k) { 892 wk = 0.5*alpha*h*PETSC_PI*PetscCoshReal(k*h)/PetscSqr(PetscCoshReal(0.5*PETSC_PI*PetscSinhReal(k*h))); 893 xk = PetscTanhReal(0.5*PETSC_PI*PetscSinhReal(k*h)); 894 x[2*k-1] = -alpha*xk+beta; 895 w[2*k-1] = wk; 896 x[2*k+0] = alpha*xk+beta; 897 w[2*k+0] = wk; 898 } 899 ierr = PetscQuadratureSetData(*q, dim, 1, npoints, x, w);CHKERRQ(ierr); 900 PetscFunctionReturn(0); 901 } 902 903 PetscErrorCode PetscDTTanhSinhIntegrate(void (*func)(PetscReal, PetscReal *), PetscReal a, PetscReal b, PetscInt digits, PetscReal *sol) 904 { 905 const PetscInt p = 16; /* Digits of precision in the evaluation */ 906 const PetscReal alpha = (b-a)/2.; /* Half-width of the integration interval */ 907 const PetscReal beta = (b+a)/2.; /* Center of the integration interval */ 908 PetscReal h = 1.0; /* Step size, length between x_k */ 909 PetscInt l = 0; /* Level of refinement, h = 2^{-l} */ 910 PetscReal osum = 0.0; /* Integral on last level */ 911 PetscReal psum = 0.0; /* Integral on the level before the last level */ 912 PetscReal sum; /* Integral on current level */ 913 PetscReal yk; /* Quadrature point 1 - x_k on reference domain [-1, 1] */ 914 PetscReal lx, rx; /* Quadrature points to the left and right of 0 on the real domain [a, b] */ 915 PetscReal wk; /* Quadrature weight at x_k */ 916 PetscReal lval, rval; /* Terms in the quadature sum to the left and right of 0 */ 917 PetscInt d; /* Digits of precision in the integral */ 918 919 PetscFunctionBegin; 920 if (digits <= 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must give a positive number of significant digits"); 921 /* Center term */ 922 func(beta, &lval); 923 sum = 0.5*alpha*PETSC_PI*lval; 924 /* */ 925 do { 926 PetscReal lterm, rterm, maxTerm = 0.0, d1, d2, d3, d4; 927 PetscInt k = 1; 928 929 ++l; 930 /* PetscPrintf(PETSC_COMM_SELF, "LEVEL %D sum: %15.15f\n", l, sum); */ 931 /* At each level of refinement, h --> h/2 and sum --> sum/2 */ 932 psum = osum; 933 osum = sum; 934 h *= 0.5; 935 sum *= 0.5; 936 do { 937 wk = 0.5*h*PETSC_PI*PetscCoshReal(k*h)/PetscSqr(PetscCoshReal(0.5*PETSC_PI*PetscSinhReal(k*h))); 938 yk = 1.0/(PetscExpReal(0.5*PETSC_PI*PetscSinhReal(k*h)) * PetscCoshReal(0.5*PETSC_PI*PetscSinhReal(k*h))); 939 lx = -alpha*(1.0 - yk)+beta; 940 rx = alpha*(1.0 - yk)+beta; 941 func(lx, &lval); 942 func(rx, &rval); 943 lterm = alpha*wk*lval; 944 maxTerm = PetscMax(PetscAbsReal(lterm), maxTerm); 945 sum += lterm; 946 rterm = alpha*wk*rval; 947 maxTerm = PetscMax(PetscAbsReal(rterm), maxTerm); 948 sum += rterm; 949 ++k; 950 /* Only need to evaluate every other point on refined levels */ 951 if (l != 1) ++k; 952 } while (PetscAbsReal(PetscLog10Real(wk)) < p); /* Only need to evaluate sum until weights are < 32 digits of precision */ 953 954 d1 = PetscLog10Real(PetscAbsReal(sum - osum)); 955 d2 = PetscLog10Real(PetscAbsReal(sum - psum)); 956 d3 = PetscLog10Real(maxTerm) - p; 957 if (PetscMax(PetscAbsReal(lterm), PetscAbsReal(rterm)) == 0.0) d4 = 0.0; 958 else d4 = PetscLog10Real(PetscMax(PetscAbsReal(lterm), PetscAbsReal(rterm))); 959 d = PetscAbsInt(PetscMin(0, PetscMax(PetscMax(PetscMax(PetscSqr(d1)/d2, 2*d1), d3), d4))); 960 } while (d < digits && l < 12); 961 *sol = sum; 962 963 PetscFunctionReturn(0); 964 } 965 966 #if defined(PETSC_HAVE_MPFR) 967 PetscErrorCode PetscDTTanhSinhIntegrateMPFR(void (*func)(PetscReal, PetscReal *), PetscReal a, PetscReal b, PetscInt digits, PetscReal *sol) 968 { 969 const PetscInt safetyFactor = 2; /* Calculate abcissa until 2*p digits */ 970 PetscInt l = 0; /* Level of refinement, h = 2^{-l} */ 971 mpfr_t alpha; /* Half-width of the integration interval */ 972 mpfr_t beta; /* Center of the integration interval */ 973 mpfr_t h; /* Step size, length between x_k */ 974 mpfr_t osum; /* Integral on last level */ 975 mpfr_t psum; /* Integral on the level before the last level */ 976 mpfr_t sum; /* Integral on current level */ 977 mpfr_t yk; /* Quadrature point 1 - x_k on reference domain [-1, 1] */ 978 mpfr_t lx, rx; /* Quadrature points to the left and right of 0 on the real domain [a, b] */ 979 mpfr_t wk; /* Quadrature weight at x_k */ 980 PetscReal lval, rval; /* Terms in the quadature sum to the left and right of 0 */ 981 PetscInt d; /* Digits of precision in the integral */ 982 mpfr_t pi2, kh, msinh, mcosh, maxTerm, curTerm, tmp; 983 984 PetscFunctionBegin; 985 if (digits <= 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must give a positive number of significant digits"); 986 /* Create high precision storage */ 987 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); 988 /* Initialization */ 989 mpfr_set_d(alpha, 0.5*(b-a), MPFR_RNDN); 990 mpfr_set_d(beta, 0.5*(b+a), MPFR_RNDN); 991 mpfr_set_d(osum, 0.0, MPFR_RNDN); 992 mpfr_set_d(psum, 0.0, MPFR_RNDN); 993 mpfr_set_d(h, 1.0, MPFR_RNDN); 994 mpfr_const_pi(pi2, MPFR_RNDN); 995 mpfr_mul_d(pi2, pi2, 0.5, MPFR_RNDN); 996 /* Center term */ 997 func(0.5*(b+a), &lval); 998 mpfr_set(sum, pi2, MPFR_RNDN); 999 mpfr_mul(sum, sum, alpha, MPFR_RNDN); 1000 mpfr_mul_d(sum, sum, lval, MPFR_RNDN); 1001 /* */ 1002 do { 1003 PetscReal d1, d2, d3, d4; 1004 PetscInt k = 1; 1005 1006 ++l; 1007 mpfr_set_d(maxTerm, 0.0, MPFR_RNDN); 1008 /* PetscPrintf(PETSC_COMM_SELF, "LEVEL %D sum: %15.15f\n", l, sum); */ 1009 /* At each level of refinement, h --> h/2 and sum --> sum/2 */ 1010 mpfr_set(psum, osum, MPFR_RNDN); 1011 mpfr_set(osum, sum, MPFR_RNDN); 1012 mpfr_mul_d(h, h, 0.5, MPFR_RNDN); 1013 mpfr_mul_d(sum, sum, 0.5, MPFR_RNDN); 1014 do { 1015 mpfr_set_si(kh, k, MPFR_RNDN); 1016 mpfr_mul(kh, kh, h, MPFR_RNDN); 1017 /* Weight */ 1018 mpfr_set(wk, h, MPFR_RNDN); 1019 mpfr_sinh_cosh(msinh, mcosh, kh, MPFR_RNDN); 1020 mpfr_mul(msinh, msinh, pi2, MPFR_RNDN); 1021 mpfr_mul(mcosh, mcosh, pi2, MPFR_RNDN); 1022 mpfr_cosh(tmp, msinh, MPFR_RNDN); 1023 mpfr_sqr(tmp, tmp, MPFR_RNDN); 1024 mpfr_mul(wk, wk, mcosh, MPFR_RNDN); 1025 mpfr_div(wk, wk, tmp, MPFR_RNDN); 1026 /* Abscissa */ 1027 mpfr_set_d(yk, 1.0, MPFR_RNDZ); 1028 mpfr_cosh(tmp, msinh, MPFR_RNDN); 1029 mpfr_div(yk, yk, tmp, MPFR_RNDZ); 1030 mpfr_exp(tmp, msinh, MPFR_RNDN); 1031 mpfr_div(yk, yk, tmp, MPFR_RNDZ); 1032 /* Quadrature points */ 1033 mpfr_sub_d(lx, yk, 1.0, MPFR_RNDZ); 1034 mpfr_mul(lx, lx, alpha, MPFR_RNDU); 1035 mpfr_add(lx, lx, beta, MPFR_RNDU); 1036 mpfr_d_sub(rx, 1.0, yk, MPFR_RNDZ); 1037 mpfr_mul(rx, rx, alpha, MPFR_RNDD); 1038 mpfr_add(rx, rx, beta, MPFR_RNDD); 1039 /* Evaluation */ 1040 func(mpfr_get_d(lx, MPFR_RNDU), &lval); 1041 func(mpfr_get_d(rx, MPFR_RNDD), &rval); 1042 /* Update */ 1043 mpfr_mul(tmp, wk, alpha, MPFR_RNDN); 1044 mpfr_mul_d(tmp, tmp, lval, MPFR_RNDN); 1045 mpfr_add(sum, sum, tmp, MPFR_RNDN); 1046 mpfr_abs(tmp, tmp, MPFR_RNDN); 1047 mpfr_max(maxTerm, maxTerm, tmp, MPFR_RNDN); 1048 mpfr_set(curTerm, tmp, MPFR_RNDN); 1049 mpfr_mul(tmp, wk, alpha, MPFR_RNDN); 1050 mpfr_mul_d(tmp, tmp, rval, MPFR_RNDN); 1051 mpfr_add(sum, sum, tmp, MPFR_RNDN); 1052 mpfr_abs(tmp, tmp, MPFR_RNDN); 1053 mpfr_max(maxTerm, maxTerm, tmp, MPFR_RNDN); 1054 mpfr_max(curTerm, curTerm, tmp, MPFR_RNDN); 1055 ++k; 1056 /* Only need to evaluate every other point on refined levels */ 1057 if (l != 1) ++k; 1058 mpfr_log10(tmp, wk, MPFR_RNDN); 1059 mpfr_abs(tmp, tmp, MPFR_RNDN); 1060 } while (mpfr_get_d(tmp, MPFR_RNDN) < safetyFactor*digits); /* Only need to evaluate sum until weights are < 32 digits of precision */ 1061 mpfr_sub(tmp, sum, osum, MPFR_RNDN); 1062 mpfr_abs(tmp, tmp, MPFR_RNDN); 1063 mpfr_log10(tmp, tmp, MPFR_RNDN); 1064 d1 = mpfr_get_d(tmp, MPFR_RNDN); 1065 mpfr_sub(tmp, sum, psum, MPFR_RNDN); 1066 mpfr_abs(tmp, tmp, MPFR_RNDN); 1067 mpfr_log10(tmp, tmp, MPFR_RNDN); 1068 d2 = mpfr_get_d(tmp, MPFR_RNDN); 1069 mpfr_log10(tmp, maxTerm, MPFR_RNDN); 1070 d3 = mpfr_get_d(tmp, MPFR_RNDN) - digits; 1071 mpfr_log10(tmp, curTerm, MPFR_RNDN); 1072 d4 = mpfr_get_d(tmp, MPFR_RNDN); 1073 d = PetscAbsInt(PetscMin(0, PetscMax(PetscMax(PetscMax(PetscSqr(d1)/d2, 2*d1), d3), d4))); 1074 } while (d < digits && l < 8); 1075 *sol = mpfr_get_d(sum, MPFR_RNDN); 1076 /* Cleanup */ 1077 mpfr_clears(alpha, beta, h, sum, osum, psum, yk, wk, lx, rx, tmp, maxTerm, curTerm, pi2, kh, msinh, mcosh, NULL); 1078 PetscFunctionReturn(0); 1079 } 1080 #else 1081 1082 PetscErrorCode PetscDTTanhSinhIntegrateMPFR(void (*func)(PetscReal, PetscReal *), PetscReal a, PetscReal b, PetscInt digits, PetscReal *sol) 1083 { 1084 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "This method will not work without MPFR. Reconfigure using --download-mpfr --download-gmp"); 1085 } 1086 #endif 1087 1088 /* Overwrites A. Can only handle full-rank problems with m>=n 1089 * A in column-major format 1090 * Ainv in row-major format 1091 * tau has length m 1092 * worksize must be >= max(1,n) 1093 */ 1094 static PetscErrorCode PetscDTPseudoInverseQR(PetscInt m,PetscInt mstride,PetscInt n,PetscReal *A_in,PetscReal *Ainv_out,PetscScalar *tau,PetscInt worksize,PetscScalar *work) 1095 { 1096 PetscErrorCode ierr; 1097 PetscBLASInt M,N,K,lda,ldb,ldwork,info; 1098 PetscScalar *A,*Ainv,*R,*Q,Alpha; 1099 1100 PetscFunctionBegin; 1101 #if defined(PETSC_USE_COMPLEX) 1102 { 1103 PetscInt i,j; 1104 ierr = PetscMalloc2(m*n,&A,m*n,&Ainv);CHKERRQ(ierr); 1105 for (j=0; j<n; j++) { 1106 for (i=0; i<m; i++) A[i+m*j] = A_in[i+mstride*j]; 1107 } 1108 mstride = m; 1109 } 1110 #else 1111 A = A_in; 1112 Ainv = Ainv_out; 1113 #endif 1114 1115 ierr = PetscBLASIntCast(m,&M);CHKERRQ(ierr); 1116 ierr = PetscBLASIntCast(n,&N);CHKERRQ(ierr); 1117 ierr = PetscBLASIntCast(mstride,&lda);CHKERRQ(ierr); 1118 ierr = PetscBLASIntCast(worksize,&ldwork);CHKERRQ(ierr); 1119 ierr = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr); 1120 PetscStackCallBLAS("LAPACKgeqrf",LAPACKgeqrf_(&M,&N,A,&lda,tau,work,&ldwork,&info)); 1121 ierr = PetscFPTrapPop();CHKERRQ(ierr); 1122 if (info) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"xGEQRF error"); 1123 R = A; /* Upper triangular part of A now contains R, the rest contains the elementary reflectors */ 1124 1125 /* Extract an explicit representation of Q */ 1126 Q = Ainv; 1127 ierr = PetscMemcpy(Q,A,mstride*n*sizeof(PetscScalar));CHKERRQ(ierr); 1128 K = N; /* full rank */ 1129 PetscStackCallBLAS("LAPACKorgqr",LAPACKorgqr_(&M,&N,&K,Q,&lda,tau,work,&ldwork,&info)); 1130 if (info) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"xORGQR/xUNGQR error"); 1131 1132 /* Compute A^{-T} = (R^{-1} Q^T)^T = Q R^{-T} */ 1133 Alpha = 1.0; 1134 ldb = lda; 1135 PetscStackCallBLAS("BLAStrsm",BLAStrsm_("Right","Upper","ConjugateTranspose","NotUnitTriangular",&M,&N,&Alpha,R,&lda,Q,&ldb)); 1136 /* Ainv is Q, overwritten with inverse */ 1137 1138 #if defined(PETSC_USE_COMPLEX) 1139 { 1140 PetscInt i; 1141 for (i=0; i<m*n; i++) Ainv_out[i] = PetscRealPart(Ainv[i]); 1142 ierr = PetscFree2(A,Ainv);CHKERRQ(ierr); 1143 } 1144 #endif 1145 PetscFunctionReturn(0); 1146 } 1147 1148 /* Computes integral of L_p' over intervals {(x0,x1),(x1,x2),...} */ 1149 static PetscErrorCode PetscDTLegendreIntegrate(PetscInt ninterval,const PetscReal *x,PetscInt ndegree,const PetscInt *degrees,PetscBool Transpose,PetscReal *B) 1150 { 1151 PetscErrorCode ierr; 1152 PetscReal *Bv; 1153 PetscInt i,j; 1154 1155 PetscFunctionBegin; 1156 ierr = PetscMalloc1((ninterval+1)*ndegree,&Bv);CHKERRQ(ierr); 1157 /* Point evaluation of L_p on all the source vertices */ 1158 ierr = PetscDTLegendreEval(ninterval+1,x,ndegree,degrees,Bv,NULL,NULL);CHKERRQ(ierr); 1159 /* Integral over each interval: \int_a^b L_p' = L_p(b)-L_p(a) */ 1160 for (i=0; i<ninterval; i++) { 1161 for (j=0; j<ndegree; j++) { 1162 if (Transpose) B[i+ninterval*j] = Bv[(i+1)*ndegree+j] - Bv[i*ndegree+j]; 1163 else B[i*ndegree+j] = Bv[(i+1)*ndegree+j] - Bv[i*ndegree+j]; 1164 } 1165 } 1166 ierr = PetscFree(Bv);CHKERRQ(ierr); 1167 PetscFunctionReturn(0); 1168 } 1169 1170 /*@ 1171 PetscDTReconstructPoly - create matrix representing polynomial reconstruction using cell intervals and evaluation at target intervals 1172 1173 Not Collective 1174 1175 Input Arguments: 1176 + degree - degree of reconstruction polynomial 1177 . nsource - number of source intervals 1178 . sourcex - sorted coordinates of source cell boundaries (length nsource+1) 1179 . ntarget - number of target intervals 1180 - targetx - sorted coordinates of target cell boundaries (length ntarget+1) 1181 1182 Output Arguments: 1183 . R - reconstruction matrix, utarget = sum_s R[t*nsource+s] * usource[s] 1184 1185 Level: advanced 1186 1187 .seealso: PetscDTLegendreEval() 1188 @*/ 1189 PetscErrorCode PetscDTReconstructPoly(PetscInt degree,PetscInt nsource,const PetscReal *sourcex,PetscInt ntarget,const PetscReal *targetx,PetscReal *R) 1190 { 1191 PetscErrorCode ierr; 1192 PetscInt i,j,k,*bdegrees,worksize; 1193 PetscReal xmin,xmax,center,hscale,*sourcey,*targety,*Bsource,*Bsinv,*Btarget; 1194 PetscScalar *tau,*work; 1195 1196 PetscFunctionBegin; 1197 PetscValidRealPointer(sourcex,3); 1198 PetscValidRealPointer(targetx,5); 1199 PetscValidRealPointer(R,6); 1200 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); 1201 #if defined(PETSC_USE_DEBUG) 1202 for (i=0; i<nsource; i++) { 1203 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]); 1204 } 1205 for (i=0; i<ntarget; i++) { 1206 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]); 1207 } 1208 #endif 1209 xmin = PetscMin(sourcex[0],targetx[0]); 1210 xmax = PetscMax(sourcex[nsource],targetx[ntarget]); 1211 center = (xmin + xmax)/2; 1212 hscale = (xmax - xmin)/2; 1213 worksize = nsource; 1214 ierr = PetscMalloc4(degree+1,&bdegrees,nsource+1,&sourcey,nsource*(degree+1),&Bsource,worksize,&work);CHKERRQ(ierr); 1215 ierr = PetscMalloc4(nsource,&tau,nsource*(degree+1),&Bsinv,ntarget+1,&targety,ntarget*(degree+1),&Btarget);CHKERRQ(ierr); 1216 for (i=0; i<=nsource; i++) sourcey[i] = (sourcex[i]-center)/hscale; 1217 for (i=0; i<=degree; i++) bdegrees[i] = i+1; 1218 ierr = PetscDTLegendreIntegrate(nsource,sourcey,degree+1,bdegrees,PETSC_TRUE,Bsource);CHKERRQ(ierr); 1219 ierr = PetscDTPseudoInverseQR(nsource,nsource,degree+1,Bsource,Bsinv,tau,nsource,work);CHKERRQ(ierr); 1220 for (i=0; i<=ntarget; i++) targety[i] = (targetx[i]-center)/hscale; 1221 ierr = PetscDTLegendreIntegrate(ntarget,targety,degree+1,bdegrees,PETSC_FALSE,Btarget);CHKERRQ(ierr); 1222 for (i=0; i<ntarget; i++) { 1223 PetscReal rowsum = 0; 1224 for (j=0; j<nsource; j++) { 1225 PetscReal sum = 0; 1226 for (k=0; k<degree+1; k++) { 1227 sum += Btarget[i*(degree+1)+k] * Bsinv[k*nsource+j]; 1228 } 1229 R[i*nsource+j] = sum; 1230 rowsum += sum; 1231 } 1232 for (j=0; j<nsource; j++) R[i*nsource+j] /= rowsum; /* normalize each row */ 1233 } 1234 ierr = PetscFree4(bdegrees,sourcey,Bsource,work);CHKERRQ(ierr); 1235 ierr = PetscFree4(tau,Bsinv,targety,Btarget);CHKERRQ(ierr); 1236 PetscFunctionReturn(0); 1237 } 1238