137045ce4SJed Brown /* Discretization tools */ 237045ce4SJed Brown 30c35b76eSJed Brown #include <petscdt.h> /*I "petscdt.h" I*/ 437045ce4SJed Brown #include <petscblaslapack.h> 5af0996ceSBarry Smith #include <petsc/private/petscimpl.h> 6af0996ceSBarry Smith #include <petsc/private/dtimpl.h> 7665c2dedSJed Brown #include <petscviewer.h> 859804f93SMatthew G. Knepley #include <petscdmplex.h> 959804f93SMatthew G. Knepley #include <petscdmshell.h> 1037045ce4SJed Brown 1198c04793SMatthew G. Knepley #if defined(PETSC_HAVE_MPFR) 1298c04793SMatthew G. Knepley #include <mpfr.h> 1398c04793SMatthew G. Knepley #endif 1498c04793SMatthew G. Knepley 15ea78f98cSLisandro Dalcin const char *const PetscDTNodeTypes[] = {"gaussjacobi", "equispaced", "tanhsinh", "PETSCDTNODES_", NULL}; 16d4afb720SToby Isaac 17e6a796c3SToby Isaac static PetscBool GolubWelschCite = PETSC_FALSE; 18e6a796c3SToby Isaac const char GolubWelschCitation[] = "@article{GolubWelsch1969,\n" 190bfcf5a5SMatthew G. Knepley " author = {Golub and Welsch},\n" 200bfcf5a5SMatthew G. Knepley " title = {Calculation of Quadrature Rules},\n" 210bfcf5a5SMatthew G. Knepley " journal = {Math. Comp.},\n" 220bfcf5a5SMatthew G. Knepley " volume = {23},\n" 230bfcf5a5SMatthew G. Knepley " number = {106},\n" 240bfcf5a5SMatthew G. Knepley " pages = {221--230},\n" 250bfcf5a5SMatthew G. Knepley " year = {1969}\n}\n"; 260bfcf5a5SMatthew G. Knepley 27c4762a1bSJed Brown /* Numerical tests in src/dm/dt/tests/ex1.c show that when computing the nodes and weights of Gauss-Jacobi 2894e21283SToby Isaac quadrature rules: 29e6a796c3SToby Isaac 3094e21283SToby Isaac - in double precision, Newton's method and Golub & Welsch both work for moderate degrees (< 100), 3194e21283SToby Isaac - in single precision, Newton's method starts producing incorrect roots around n = 15, but 3294e21283SToby Isaac the weights from Golub & Welsch become a problem before then: they produces errors 3394e21283SToby Isaac in computing the Jacobi-polynomial Gram matrix around n = 6. 3494e21283SToby Isaac 3594e21283SToby Isaac So we default to Newton's method (required fewer dependencies) */ 3694e21283SToby Isaac PetscBool PetscDTGaussQuadratureNewton_Internal = PETSC_TRUE; 372cd22861SMatthew G. Knepley 382cd22861SMatthew G. Knepley PetscClassId PETSCQUADRATURE_CLASSID = 0; 392cd22861SMatthew G. Knepley 4040d8ff71SMatthew G. Knepley /*@ 4140d8ff71SMatthew G. Knepley PetscQuadratureCreate - Create a PetscQuadrature object 4240d8ff71SMatthew G. Knepley 43d083f849SBarry Smith Collective 4440d8ff71SMatthew G. Knepley 4540d8ff71SMatthew G. Knepley Input Parameter: 4640d8ff71SMatthew G. Knepley . comm - The communicator for the PetscQuadrature object 4740d8ff71SMatthew G. Knepley 4840d8ff71SMatthew G. Knepley Output Parameter: 4940d8ff71SMatthew G. Knepley . q - The PetscQuadrature object 5040d8ff71SMatthew G. Knepley 5140d8ff71SMatthew G. Knepley Level: beginner 5240d8ff71SMatthew G. Knepley 5340d8ff71SMatthew G. Knepley .seealso: PetscQuadratureDestroy(), PetscQuadratureGetData() 5440d8ff71SMatthew G. Knepley @*/ 5521454ff5SMatthew G. Knepley PetscErrorCode PetscQuadratureCreate(MPI_Comm comm, PetscQuadrature *q) 5621454ff5SMatthew G. Knepley { 5721454ff5SMatthew G. Knepley PetscErrorCode ierr; 5821454ff5SMatthew G. Knepley 5921454ff5SMatthew G. Knepley PetscFunctionBegin; 6021454ff5SMatthew G. Knepley PetscValidPointer(q, 2); 612cd22861SMatthew G. Knepley ierr = DMInitializePackage();CHKERRQ(ierr); 622cd22861SMatthew G. Knepley ierr = PetscHeaderCreate(*q,PETSCQUADRATURE_CLASSID,"PetscQuadrature","Quadrature","DT",comm,PetscQuadratureDestroy,PetscQuadratureView);CHKERRQ(ierr); 6321454ff5SMatthew G. Knepley (*q)->dim = -1; 64a6b92713SMatthew G. Knepley (*q)->Nc = 1; 65bcede257SMatthew G. Knepley (*q)->order = -1; 6621454ff5SMatthew G. Knepley (*q)->numPoints = 0; 6721454ff5SMatthew G. Knepley (*q)->points = NULL; 6821454ff5SMatthew G. Knepley (*q)->weights = NULL; 6921454ff5SMatthew G. Knepley PetscFunctionReturn(0); 7021454ff5SMatthew G. Knepley } 7121454ff5SMatthew G. Knepley 72c9638911SMatthew G. Knepley /*@ 73c9638911SMatthew G. Knepley PetscQuadratureDuplicate - Create a deep copy of the PetscQuadrature object 74c9638911SMatthew G. Knepley 75d083f849SBarry Smith Collective on q 76c9638911SMatthew G. Knepley 77c9638911SMatthew G. Knepley Input Parameter: 78c9638911SMatthew G. Knepley . q - The PetscQuadrature object 79c9638911SMatthew G. Knepley 80c9638911SMatthew G. Knepley Output Parameter: 81c9638911SMatthew G. Knepley . r - The new PetscQuadrature object 82c9638911SMatthew G. Knepley 83c9638911SMatthew G. Knepley Level: beginner 84c9638911SMatthew G. Knepley 85c9638911SMatthew G. Knepley .seealso: PetscQuadratureCreate(), PetscQuadratureDestroy(), PetscQuadratureGetData() 86c9638911SMatthew G. Knepley @*/ 87c9638911SMatthew G. Knepley PetscErrorCode PetscQuadratureDuplicate(PetscQuadrature q, PetscQuadrature *r) 88c9638911SMatthew G. Knepley { 89a6b92713SMatthew G. Knepley PetscInt order, dim, Nc, Nq; 90c9638911SMatthew G. Knepley const PetscReal *points, *weights; 91c9638911SMatthew G. Knepley PetscReal *p, *w; 92c9638911SMatthew G. Knepley PetscErrorCode ierr; 93c9638911SMatthew G. Knepley 94c9638911SMatthew G. Knepley PetscFunctionBegin; 95064a246eSJacob Faibussowitsch PetscValidPointer(q, 1); 96c9638911SMatthew G. Knepley ierr = PetscQuadratureCreate(PetscObjectComm((PetscObject) q), r);CHKERRQ(ierr); 97c9638911SMatthew G. Knepley ierr = PetscQuadratureGetOrder(q, &order);CHKERRQ(ierr); 98c9638911SMatthew G. Knepley ierr = PetscQuadratureSetOrder(*r, order);CHKERRQ(ierr); 99a6b92713SMatthew G. Knepley ierr = PetscQuadratureGetData(q, &dim, &Nc, &Nq, &points, &weights);CHKERRQ(ierr); 100c9638911SMatthew G. Knepley ierr = PetscMalloc1(Nq*dim, &p);CHKERRQ(ierr); 101f0a0bfafSMatthew G. Knepley ierr = PetscMalloc1(Nq*Nc, &w);CHKERRQ(ierr); 102580bdb30SBarry Smith ierr = PetscArraycpy(p, points, Nq*dim);CHKERRQ(ierr); 103580bdb30SBarry Smith ierr = PetscArraycpy(w, weights, Nc * Nq);CHKERRQ(ierr); 104a6b92713SMatthew G. Knepley ierr = PetscQuadratureSetData(*r, dim, Nc, Nq, p, w);CHKERRQ(ierr); 105c9638911SMatthew G. Knepley PetscFunctionReturn(0); 106c9638911SMatthew G. Knepley } 107c9638911SMatthew G. Knepley 10840d8ff71SMatthew G. Knepley /*@ 10940d8ff71SMatthew G. Knepley PetscQuadratureDestroy - Destroys a PetscQuadrature object 11040d8ff71SMatthew G. Knepley 111d083f849SBarry Smith Collective on q 11240d8ff71SMatthew G. Knepley 11340d8ff71SMatthew G. Knepley Input Parameter: 11440d8ff71SMatthew G. Knepley . q - The PetscQuadrature object 11540d8ff71SMatthew G. Knepley 11640d8ff71SMatthew G. Knepley Level: beginner 11740d8ff71SMatthew G. Knepley 11840d8ff71SMatthew G. Knepley .seealso: PetscQuadratureCreate(), PetscQuadratureGetData() 11940d8ff71SMatthew G. Knepley @*/ 120bfa639d9SMatthew G. Knepley PetscErrorCode PetscQuadratureDestroy(PetscQuadrature *q) 121bfa639d9SMatthew G. Knepley { 122bfa639d9SMatthew G. Knepley PetscErrorCode ierr; 123bfa639d9SMatthew G. Knepley 124bfa639d9SMatthew G. Knepley PetscFunctionBegin; 12521454ff5SMatthew G. Knepley if (!*q) PetscFunctionReturn(0); 1262cd22861SMatthew G. Knepley PetscValidHeaderSpecific((*q),PETSCQUADRATURE_CLASSID,1); 12721454ff5SMatthew G. Knepley if (--((PetscObject)(*q))->refct > 0) { 12821454ff5SMatthew G. Knepley *q = NULL; 12921454ff5SMatthew G. Knepley PetscFunctionReturn(0); 13021454ff5SMatthew G. Knepley } 13121454ff5SMatthew G. Knepley ierr = PetscFree((*q)->points);CHKERRQ(ierr); 13221454ff5SMatthew G. Knepley ierr = PetscFree((*q)->weights);CHKERRQ(ierr); 13321454ff5SMatthew G. Knepley ierr = PetscHeaderDestroy(q);CHKERRQ(ierr); 13421454ff5SMatthew G. Knepley PetscFunctionReturn(0); 13521454ff5SMatthew G. Knepley } 13621454ff5SMatthew G. Knepley 137bcede257SMatthew G. Knepley /*@ 138a6b92713SMatthew G. Knepley PetscQuadratureGetOrder - Return the order of the method 139bcede257SMatthew G. Knepley 140bcede257SMatthew G. Knepley Not collective 141bcede257SMatthew G. Knepley 142bcede257SMatthew G. Knepley Input Parameter: 143bcede257SMatthew G. Knepley . q - The PetscQuadrature object 144bcede257SMatthew G. Knepley 145bcede257SMatthew G. Knepley Output Parameter: 146bcede257SMatthew G. Knepley . order - The order of the quadrature, i.e. the highest degree polynomial that is exactly integrated 147bcede257SMatthew G. Knepley 148bcede257SMatthew G. Knepley Level: intermediate 149bcede257SMatthew G. Knepley 150bcede257SMatthew G. Knepley .seealso: PetscQuadratureSetOrder(), PetscQuadratureGetData(), PetscQuadratureSetData() 151bcede257SMatthew G. Knepley @*/ 152bcede257SMatthew G. Knepley PetscErrorCode PetscQuadratureGetOrder(PetscQuadrature q, PetscInt *order) 153bcede257SMatthew G. Knepley { 154bcede257SMatthew G. Knepley PetscFunctionBegin; 1552cd22861SMatthew G. Knepley PetscValidHeaderSpecific(q, PETSCQUADRATURE_CLASSID, 1); 156bcede257SMatthew G. Knepley PetscValidPointer(order, 2); 157bcede257SMatthew G. Knepley *order = q->order; 158bcede257SMatthew G. Knepley PetscFunctionReturn(0); 159bcede257SMatthew G. Knepley } 160bcede257SMatthew G. Knepley 161bcede257SMatthew G. Knepley /*@ 162a6b92713SMatthew G. Knepley PetscQuadratureSetOrder - Return the order of the method 163bcede257SMatthew G. Knepley 164bcede257SMatthew G. Knepley Not collective 165bcede257SMatthew G. Knepley 166bcede257SMatthew G. Knepley Input Parameters: 167bcede257SMatthew G. Knepley + q - The PetscQuadrature object 168bcede257SMatthew G. Knepley - order - The order of the quadrature, i.e. the highest degree polynomial that is exactly integrated 169bcede257SMatthew G. Knepley 170bcede257SMatthew G. Knepley Level: intermediate 171bcede257SMatthew G. Knepley 172bcede257SMatthew G. Knepley .seealso: PetscQuadratureGetOrder(), PetscQuadratureGetData(), PetscQuadratureSetData() 173bcede257SMatthew G. Knepley @*/ 174bcede257SMatthew G. Knepley PetscErrorCode PetscQuadratureSetOrder(PetscQuadrature q, PetscInt order) 175bcede257SMatthew G. Knepley { 176bcede257SMatthew G. Knepley PetscFunctionBegin; 1772cd22861SMatthew G. Knepley PetscValidHeaderSpecific(q, PETSCQUADRATURE_CLASSID, 1); 178bcede257SMatthew G. Knepley q->order = order; 179bcede257SMatthew G. Knepley PetscFunctionReturn(0); 180bcede257SMatthew G. Knepley } 181bcede257SMatthew G. Knepley 182a6b92713SMatthew G. Knepley /*@ 183a6b92713SMatthew G. Knepley PetscQuadratureGetNumComponents - Return the number of components for functions to be integrated 184a6b92713SMatthew G. Knepley 185a6b92713SMatthew G. Knepley Not collective 186a6b92713SMatthew G. Knepley 187a6b92713SMatthew G. Knepley Input Parameter: 188a6b92713SMatthew G. Knepley . q - The PetscQuadrature object 189a6b92713SMatthew G. Knepley 190a6b92713SMatthew G. Knepley Output Parameter: 191a6b92713SMatthew G. Knepley . Nc - The number of components 192a6b92713SMatthew G. Knepley 193a6b92713SMatthew G. Knepley Note: We are performing an integral int f(x) . w(x) dx, where both f and w (the weight) have Nc components. 194a6b92713SMatthew G. Knepley 195a6b92713SMatthew G. Knepley Level: intermediate 196a6b92713SMatthew G. Knepley 197a6b92713SMatthew G. Knepley .seealso: PetscQuadratureSetNumComponents(), PetscQuadratureGetData(), PetscQuadratureSetData() 198a6b92713SMatthew G. Knepley @*/ 199a6b92713SMatthew G. Knepley PetscErrorCode PetscQuadratureGetNumComponents(PetscQuadrature q, PetscInt *Nc) 200a6b92713SMatthew G. Knepley { 201a6b92713SMatthew G. Knepley PetscFunctionBegin; 2022cd22861SMatthew G. Knepley PetscValidHeaderSpecific(q, PETSCQUADRATURE_CLASSID, 1); 203a6b92713SMatthew G. Knepley PetscValidPointer(Nc, 2); 204a6b92713SMatthew G. Knepley *Nc = q->Nc; 205a6b92713SMatthew G. Knepley PetscFunctionReturn(0); 206a6b92713SMatthew G. Knepley } 207a6b92713SMatthew G. Knepley 208a6b92713SMatthew G. Knepley /*@ 209a6b92713SMatthew G. Knepley PetscQuadratureSetNumComponents - Return the number of components for functions to be integrated 210a6b92713SMatthew G. Knepley 211a6b92713SMatthew G. Knepley Not collective 212a6b92713SMatthew G. Knepley 213a6b92713SMatthew G. Knepley Input Parameters: 214a6b92713SMatthew G. Knepley + q - The PetscQuadrature object 215a6b92713SMatthew G. Knepley - Nc - The number of components 216a6b92713SMatthew G. Knepley 217a6b92713SMatthew G. Knepley Note: We are performing an integral int f(x) . w(x) dx, where both f and w (the weight) have Nc components. 218a6b92713SMatthew G. Knepley 219a6b92713SMatthew G. Knepley Level: intermediate 220a6b92713SMatthew G. Knepley 221a6b92713SMatthew G. Knepley .seealso: PetscQuadratureGetNumComponents(), PetscQuadratureGetData(), PetscQuadratureSetData() 222a6b92713SMatthew G. Knepley @*/ 223a6b92713SMatthew G. Knepley PetscErrorCode PetscQuadratureSetNumComponents(PetscQuadrature q, PetscInt Nc) 224a6b92713SMatthew G. Knepley { 225a6b92713SMatthew G. Knepley PetscFunctionBegin; 2262cd22861SMatthew G. Knepley PetscValidHeaderSpecific(q, PETSCQUADRATURE_CLASSID, 1); 227a6b92713SMatthew G. Knepley q->Nc = Nc; 228a6b92713SMatthew G. Knepley PetscFunctionReturn(0); 229a6b92713SMatthew G. Knepley } 230a6b92713SMatthew G. Knepley 23140d8ff71SMatthew G. Knepley /*@C 23240d8ff71SMatthew G. Knepley PetscQuadratureGetData - Returns the data defining the quadrature 23340d8ff71SMatthew G. Knepley 23440d8ff71SMatthew G. Knepley Not collective 23540d8ff71SMatthew G. Knepley 23640d8ff71SMatthew G. Knepley Input Parameter: 23740d8ff71SMatthew G. Knepley . q - The PetscQuadrature object 23840d8ff71SMatthew G. Knepley 23940d8ff71SMatthew G. Knepley Output Parameters: 24040d8ff71SMatthew G. Knepley + dim - The spatial dimension 241805e7170SToby Isaac . Nc - The number of components 24240d8ff71SMatthew G. Knepley . npoints - The number of quadrature points 24340d8ff71SMatthew G. Knepley . points - The coordinates of each quadrature point 24440d8ff71SMatthew G. Knepley - weights - The weight of each quadrature point 24540d8ff71SMatthew G. Knepley 24640d8ff71SMatthew G. Knepley Level: intermediate 24740d8ff71SMatthew G. Knepley 24895452b02SPatrick Sanan Fortran Notes: 24995452b02SPatrick Sanan From Fortran you must call PetscQuadratureRestoreData() when you are done with the data 2501fd49c25SBarry Smith 25140d8ff71SMatthew G. Knepley .seealso: PetscQuadratureCreate(), PetscQuadratureSetData() 25240d8ff71SMatthew G. Knepley @*/ 253a6b92713SMatthew G. Knepley PetscErrorCode PetscQuadratureGetData(PetscQuadrature q, PetscInt *dim, PetscInt *Nc, PetscInt *npoints, const PetscReal *points[], const PetscReal *weights[]) 25421454ff5SMatthew G. Knepley { 25521454ff5SMatthew G. Knepley PetscFunctionBegin; 2562cd22861SMatthew G. Knepley PetscValidHeaderSpecific(q, PETSCQUADRATURE_CLASSID, 1); 25721454ff5SMatthew G. Knepley if (dim) { 25821454ff5SMatthew G. Knepley PetscValidPointer(dim, 2); 25921454ff5SMatthew G. Knepley *dim = q->dim; 26021454ff5SMatthew G. Knepley } 261a6b92713SMatthew G. Knepley if (Nc) { 262a6b92713SMatthew G. Knepley PetscValidPointer(Nc, 3); 263a6b92713SMatthew G. Knepley *Nc = q->Nc; 264a6b92713SMatthew G. Knepley } 26521454ff5SMatthew G. Knepley if (npoints) { 266a6b92713SMatthew G. Knepley PetscValidPointer(npoints, 4); 26721454ff5SMatthew G. Knepley *npoints = q->numPoints; 26821454ff5SMatthew G. Knepley } 26921454ff5SMatthew G. Knepley if (points) { 270a6b92713SMatthew G. Knepley PetscValidPointer(points, 5); 27121454ff5SMatthew G. Knepley *points = q->points; 27221454ff5SMatthew G. Knepley } 27321454ff5SMatthew G. Knepley if (weights) { 274a6b92713SMatthew G. Knepley PetscValidPointer(weights, 6); 27521454ff5SMatthew G. Knepley *weights = q->weights; 27621454ff5SMatthew G. Knepley } 27721454ff5SMatthew G. Knepley PetscFunctionReturn(0); 27821454ff5SMatthew G. Knepley } 27921454ff5SMatthew G. Knepley 280*4f9ab2b4SJed Brown /*@ 281*4f9ab2b4SJed Brown PetscQuadratureEqual - determine whether two quadratures are equivalent 282*4f9ab2b4SJed Brown 283*4f9ab2b4SJed Brown Input Parameters: 284*4f9ab2b4SJed Brown + A - A PetscQuadrature object 285*4f9ab2b4SJed Brown - B - Another PetscQuadrature object 286*4f9ab2b4SJed Brown 287*4f9ab2b4SJed Brown Output Parameters: 288*4f9ab2b4SJed Brown . equal - PETSC_TRUE if the quadratures are the same 289*4f9ab2b4SJed Brown 290*4f9ab2b4SJed Brown Level: intermediate 291*4f9ab2b4SJed Brown 292*4f9ab2b4SJed Brown .seealso: PetscQuadratureCreate() 293*4f9ab2b4SJed Brown @*/ 294*4f9ab2b4SJed Brown PetscErrorCode PetscQuadratureEqual(PetscQuadrature A, PetscQuadrature B, PetscBool *equal) 295*4f9ab2b4SJed Brown { 296*4f9ab2b4SJed Brown PetscFunctionBegin; 297*4f9ab2b4SJed Brown PetscValidHeaderSpecific(A, PETSCQUADRATURE_CLASSID, 1); 298*4f9ab2b4SJed Brown PetscValidHeaderSpecific(B, PETSCQUADRATURE_CLASSID, 2); 299*4f9ab2b4SJed Brown PetscValidBoolPointer(equal, 3); 300*4f9ab2b4SJed Brown *equal = PETSC_FALSE; 301*4f9ab2b4SJed Brown if (A->dim != B->dim || A->Nc != B->Nc || A->order != B->order || A->numPoints != B->numPoints) { 302*4f9ab2b4SJed Brown PetscFunctionReturn(0); 303*4f9ab2b4SJed Brown } 304*4f9ab2b4SJed Brown for (PetscInt i=0; i<A->numPoints*A->dim; i++) { 305*4f9ab2b4SJed Brown if (PetscAbsReal(A->points[i] - B->points[i]) > PETSC_SMALL) { 306*4f9ab2b4SJed Brown PetscFunctionReturn(0); 307*4f9ab2b4SJed Brown } 308*4f9ab2b4SJed Brown } 309*4f9ab2b4SJed Brown if (!A->weights && !B->weights) { 310*4f9ab2b4SJed Brown *equal = PETSC_TRUE; 311*4f9ab2b4SJed Brown PetscFunctionReturn(0); 312*4f9ab2b4SJed Brown } 313*4f9ab2b4SJed Brown if (A->weights && B->weights) { 314*4f9ab2b4SJed Brown for (PetscInt i=0; i<A->numPoints; i++) { 315*4f9ab2b4SJed Brown if (PetscAbsReal(A->weights[i] - B->weights[i]) > PETSC_SMALL) { 316*4f9ab2b4SJed Brown PetscFunctionReturn(0); 317*4f9ab2b4SJed Brown } 318*4f9ab2b4SJed Brown } 319*4f9ab2b4SJed Brown *equal = PETSC_TRUE; 320*4f9ab2b4SJed Brown } 321*4f9ab2b4SJed Brown PetscFunctionReturn(0); 322*4f9ab2b4SJed Brown } 323*4f9ab2b4SJed Brown 324907761f8SToby Isaac static PetscErrorCode PetscDTJacobianInverse_Internal(PetscInt m, PetscInt n, const PetscReal J[], PetscReal Jinv[]) 325907761f8SToby Isaac { 326907761f8SToby Isaac PetscScalar *Js, *Jinvs; 327907761f8SToby Isaac PetscInt i, j, k; 328907761f8SToby Isaac PetscBLASInt bm, bn, info; 329907761f8SToby Isaac PetscErrorCode ierr; 330907761f8SToby Isaac 331907761f8SToby Isaac PetscFunctionBegin; 332d4afb720SToby Isaac if (!m || !n) PetscFunctionReturn(0); 333907761f8SToby Isaac ierr = PetscBLASIntCast(m, &bm);CHKERRQ(ierr); 334907761f8SToby Isaac ierr = PetscBLASIntCast(n, &bn);CHKERRQ(ierr); 335907761f8SToby Isaac #if defined(PETSC_USE_COMPLEX) 336907761f8SToby Isaac ierr = PetscMalloc2(m*n, &Js, m*n, &Jinvs);CHKERRQ(ierr); 33728222859SToby Isaac for (i = 0; i < m*n; i++) Js[i] = J[i]; 338907761f8SToby Isaac #else 339907761f8SToby Isaac Js = (PetscReal *) J; 340907761f8SToby Isaac Jinvs = Jinv; 341907761f8SToby Isaac #endif 342907761f8SToby Isaac if (m == n) { 343907761f8SToby Isaac PetscBLASInt *pivots; 344907761f8SToby Isaac PetscScalar *W; 345907761f8SToby Isaac 346907761f8SToby Isaac ierr = PetscMalloc2(m, &pivots, m, &W);CHKERRQ(ierr); 347907761f8SToby Isaac 348907761f8SToby Isaac ierr = PetscArraycpy(Jinvs, Js, m * m);CHKERRQ(ierr); 349907761f8SToby Isaac PetscStackCallBLAS("LAPACKgetrf", LAPACKgetrf_(&bm, &bm, Jinvs, &bm, pivots, &info)); 3502c71b3e2SJacob Faibussowitsch PetscCheckFalse(info,PETSC_COMM_SELF,PETSC_ERR_LIB,"Error returned from LAPACKgetrf %D",(PetscInt)info); 351907761f8SToby Isaac PetscStackCallBLAS("LAPACKgetri", LAPACKgetri_(&bm, Jinvs, &bm, pivots, W, &bm, &info)); 3522c71b3e2SJacob Faibussowitsch PetscCheckFalse(info,PETSC_COMM_SELF,PETSC_ERR_LIB,"Error returned from LAPACKgetri %D",(PetscInt)info); 353907761f8SToby Isaac ierr = PetscFree2(pivots, W);CHKERRQ(ierr); 354907761f8SToby Isaac } else if (m < n) { 355907761f8SToby Isaac PetscScalar *JJT; 356907761f8SToby Isaac PetscBLASInt *pivots; 357907761f8SToby Isaac PetscScalar *W; 358907761f8SToby Isaac 359907761f8SToby Isaac ierr = PetscMalloc1(m*m, &JJT);CHKERRQ(ierr); 360907761f8SToby Isaac ierr = PetscMalloc2(m, &pivots, m, &W);CHKERRQ(ierr); 361907761f8SToby Isaac for (i = 0; i < m; i++) { 362907761f8SToby Isaac for (j = 0; j < m; j++) { 363907761f8SToby Isaac PetscScalar val = 0.; 364907761f8SToby Isaac 365907761f8SToby Isaac for (k = 0; k < n; k++) val += Js[i * n + k] * Js[j * n + k]; 366907761f8SToby Isaac JJT[i * m + j] = val; 367907761f8SToby Isaac } 368907761f8SToby Isaac } 369907761f8SToby Isaac 370907761f8SToby Isaac PetscStackCallBLAS("LAPACKgetrf", LAPACKgetrf_(&bm, &bm, JJT, &bm, pivots, &info)); 3712c71b3e2SJacob Faibussowitsch PetscCheckFalse(info,PETSC_COMM_SELF,PETSC_ERR_LIB,"Error returned from LAPACKgetrf %D",(PetscInt)info); 372907761f8SToby Isaac PetscStackCallBLAS("LAPACKgetri", LAPACKgetri_(&bm, JJT, &bm, pivots, W, &bm, &info)); 3732c71b3e2SJacob Faibussowitsch PetscCheckFalse(info,PETSC_COMM_SELF,PETSC_ERR_LIB,"Error returned from LAPACKgetri %D",(PetscInt)info); 374907761f8SToby Isaac for (i = 0; i < n; i++) { 375907761f8SToby Isaac for (j = 0; j < m; j++) { 376907761f8SToby Isaac PetscScalar val = 0.; 377907761f8SToby Isaac 378907761f8SToby Isaac for (k = 0; k < m; k++) val += Js[k * n + i] * JJT[k * m + j]; 379907761f8SToby Isaac Jinvs[i * m + j] = val; 380907761f8SToby Isaac } 381907761f8SToby Isaac } 382907761f8SToby Isaac ierr = PetscFree2(pivots, W);CHKERRQ(ierr); 383907761f8SToby Isaac ierr = PetscFree(JJT);CHKERRQ(ierr); 384907761f8SToby Isaac } else { 385907761f8SToby Isaac PetscScalar *JTJ; 386907761f8SToby Isaac PetscBLASInt *pivots; 387907761f8SToby Isaac PetscScalar *W; 388907761f8SToby Isaac 389907761f8SToby Isaac ierr = PetscMalloc1(n*n, &JTJ);CHKERRQ(ierr); 390907761f8SToby Isaac ierr = PetscMalloc2(n, &pivots, n, &W);CHKERRQ(ierr); 391907761f8SToby Isaac for (i = 0; i < n; i++) { 392907761f8SToby Isaac for (j = 0; j < n; j++) { 393907761f8SToby Isaac PetscScalar val = 0.; 394907761f8SToby Isaac 395907761f8SToby Isaac for (k = 0; k < m; k++) val += Js[k * n + i] * Js[k * n + j]; 396907761f8SToby Isaac JTJ[i * n + j] = val; 397907761f8SToby Isaac } 398907761f8SToby Isaac } 399907761f8SToby Isaac 400d4afb720SToby Isaac PetscStackCallBLAS("LAPACKgetrf", LAPACKgetrf_(&bn, &bn, JTJ, &bn, pivots, &info)); 4012c71b3e2SJacob Faibussowitsch PetscCheckFalse(info,PETSC_COMM_SELF,PETSC_ERR_LIB,"Error returned from LAPACKgetrf %D",(PetscInt)info); 402907761f8SToby Isaac PetscStackCallBLAS("LAPACKgetri", LAPACKgetri_(&bn, JTJ, &bn, pivots, W, &bn, &info)); 4032c71b3e2SJacob Faibussowitsch PetscCheckFalse(info,PETSC_COMM_SELF,PETSC_ERR_LIB,"Error returned from LAPACKgetri %D",(PetscInt)info); 404907761f8SToby Isaac for (i = 0; i < n; i++) { 405907761f8SToby Isaac for (j = 0; j < m; j++) { 406907761f8SToby Isaac PetscScalar val = 0.; 407907761f8SToby Isaac 408907761f8SToby Isaac for (k = 0; k < n; k++) val += JTJ[i * n + k] * Js[j * n + k]; 409907761f8SToby Isaac Jinvs[i * m + j] = val; 410907761f8SToby Isaac } 411907761f8SToby Isaac } 412907761f8SToby Isaac ierr = PetscFree2(pivots, W);CHKERRQ(ierr); 413907761f8SToby Isaac ierr = PetscFree(JTJ);CHKERRQ(ierr); 414907761f8SToby Isaac } 415907761f8SToby Isaac #if defined(PETSC_USE_COMPLEX) 41628222859SToby Isaac for (i = 0; i < m*n; i++) Jinv[i] = PetscRealPart(Jinvs[i]); 417907761f8SToby Isaac ierr = PetscFree2(Js, Jinvs);CHKERRQ(ierr); 418907761f8SToby Isaac #endif 419907761f8SToby Isaac PetscFunctionReturn(0); 420907761f8SToby Isaac } 421907761f8SToby Isaac 422907761f8SToby Isaac /*@ 423907761f8SToby Isaac PetscQuadraturePushForward - Push forward a quadrature functional under an affine transformation. 424907761f8SToby Isaac 425907761f8SToby Isaac Collecive on PetscQuadrature 426907761f8SToby Isaac 4274165533cSJose E. Roman Input Parameters: 428907761f8SToby Isaac + q - the quadrature functional 429907761f8SToby Isaac . imageDim - the dimension of the image of the transformation 430907761f8SToby Isaac . origin - a point in the original space 431907761f8SToby Isaac . originImage - the image of the origin under the transformation 432907761f8SToby Isaac . J - the Jacobian of the image: an [imageDim x dim] matrix in row major order 43328222859SToby Isaac - formDegree - transform the quadrature weights as k-forms of this form degree (if the number of components is a multiple of (dim choose formDegree), it is assumed that they represent multiple k-forms) [see PetscDTAltVPullback() for interpretation of formDegree] 434907761f8SToby Isaac 4354165533cSJose E. Roman Output Parameters: 436907761f8SToby Isaac . Jinvstarq - a quadrature rule where each point is the image of a point in the original quadrature rule, and where the k-form weights have been pulled-back by the pseudoinverse of J to the k-form weights in the image space. 437907761f8SToby Isaac 438907761f8SToby Isaac Note: the new quadrature rule will have a different number of components if spaces have different dimensions. For example, pushing a 2-form forward from a two dimensional space to a three dimensional space changes the number of components from 1 to 3. 439907761f8SToby Isaac 4406c877ef6SSatish Balay Level: intermediate 4416c877ef6SSatish Balay 442907761f8SToby Isaac .seealso: PetscDTAltVPullback(), PetscDTAltVPullbackMatrix() 443907761f8SToby Isaac @*/ 44428222859SToby Isaac PetscErrorCode PetscQuadraturePushForward(PetscQuadrature q, PetscInt imageDim, const PetscReal origin[], const PetscReal originImage[], const PetscReal J[], PetscInt formDegree, PetscQuadrature *Jinvstarq) 445907761f8SToby Isaac { 446907761f8SToby Isaac PetscInt dim, Nc, imageNc, formSize, Ncopies, imageFormSize, Npoints, pt, i, j, c; 447907761f8SToby Isaac const PetscReal *points; 448907761f8SToby Isaac const PetscReal *weights; 449907761f8SToby Isaac PetscReal *imagePoints, *imageWeights; 450907761f8SToby Isaac PetscReal *Jinv; 451907761f8SToby Isaac PetscReal *Jinvstar; 452907761f8SToby Isaac PetscErrorCode ierr; 453907761f8SToby Isaac 454907761f8SToby Isaac PetscFunctionBegin; 455d4afb720SToby Isaac PetscValidHeaderSpecific(q, PETSCQUADRATURE_CLASSID, 1); 4562c71b3e2SJacob Faibussowitsch PetscCheckFalse(imageDim < PetscAbsInt(formDegree),PetscObjectComm((PetscObject)q), PETSC_ERR_ARG_INCOMP, "Cannot represent a %D-form in %D dimensions", PetscAbsInt(formDegree), imageDim); 457907761f8SToby Isaac ierr = PetscQuadratureGetData(q, &dim, &Nc, &Npoints, &points, &weights);CHKERRQ(ierr); 45828222859SToby Isaac ierr = PetscDTBinomialInt(dim, PetscAbsInt(formDegree), &formSize);CHKERRQ(ierr); 4592c71b3e2SJacob Faibussowitsch PetscCheckFalse(Nc % formSize,PetscObjectComm((PetscObject)q), PETSC_ERR_ARG_INCOMP, "Number of components %D is not a multiple of formSize %D", Nc, formSize); 460907761f8SToby Isaac Ncopies = Nc / formSize; 46128222859SToby Isaac ierr = PetscDTBinomialInt(imageDim, PetscAbsInt(formDegree), &imageFormSize);CHKERRQ(ierr); 462907761f8SToby Isaac imageNc = Ncopies * imageFormSize; 463907761f8SToby Isaac ierr = PetscMalloc1(Npoints * imageDim, &imagePoints);CHKERRQ(ierr); 464907761f8SToby Isaac ierr = PetscMalloc1(Npoints * imageNc, &imageWeights);CHKERRQ(ierr); 465907761f8SToby Isaac ierr = PetscMalloc2(imageDim * dim, &Jinv, formSize * imageFormSize, &Jinvstar);CHKERRQ(ierr); 466d4afb720SToby Isaac ierr = PetscDTJacobianInverse_Internal(imageDim, dim, J, Jinv);CHKERRQ(ierr); 46728222859SToby Isaac ierr = PetscDTAltVPullbackMatrix(imageDim, dim, Jinv, formDegree, Jinvstar);CHKERRQ(ierr); 468907761f8SToby Isaac for (pt = 0; pt < Npoints; pt++) { 469907761f8SToby Isaac const PetscReal *point = &points[pt * dim]; 470907761f8SToby Isaac PetscReal *imagePoint = &imagePoints[pt * imageDim]; 471907761f8SToby Isaac 472907761f8SToby Isaac for (i = 0; i < imageDim; i++) { 473907761f8SToby Isaac PetscReal val = originImage[i]; 474907761f8SToby Isaac 475907761f8SToby Isaac for (j = 0; j < dim; j++) val += J[i * dim + j] * (point[j] - origin[j]); 476907761f8SToby Isaac imagePoint[i] = val; 477907761f8SToby Isaac } 478907761f8SToby Isaac for (c = 0; c < Ncopies; c++) { 479907761f8SToby Isaac const PetscReal *form = &weights[pt * Nc + c * formSize]; 480907761f8SToby Isaac PetscReal *imageForm = &imageWeights[pt * imageNc + c * imageFormSize]; 481907761f8SToby Isaac 482907761f8SToby Isaac for (i = 0; i < imageFormSize; i++) { 483907761f8SToby Isaac PetscReal val = 0.; 484907761f8SToby Isaac 485907761f8SToby Isaac for (j = 0; j < formSize; j++) val += Jinvstar[i * formSize + j] * form[j]; 486907761f8SToby Isaac imageForm[i] = val; 487907761f8SToby Isaac } 488907761f8SToby Isaac } 489907761f8SToby Isaac } 490907761f8SToby Isaac ierr = PetscQuadratureCreate(PetscObjectComm((PetscObject)q), Jinvstarq);CHKERRQ(ierr); 491907761f8SToby Isaac ierr = PetscQuadratureSetData(*Jinvstarq, imageDim, imageNc, Npoints, imagePoints, imageWeights);CHKERRQ(ierr); 492907761f8SToby Isaac ierr = PetscFree2(Jinv, Jinvstar);CHKERRQ(ierr); 493907761f8SToby Isaac PetscFunctionReturn(0); 494907761f8SToby Isaac } 495907761f8SToby Isaac 49640d8ff71SMatthew G. Knepley /*@C 49740d8ff71SMatthew G. Knepley PetscQuadratureSetData - Sets the data defining the quadrature 49840d8ff71SMatthew G. Knepley 49940d8ff71SMatthew G. Knepley Not collective 50040d8ff71SMatthew G. Knepley 50140d8ff71SMatthew G. Knepley Input Parameters: 50240d8ff71SMatthew G. Knepley + q - The PetscQuadrature object 50340d8ff71SMatthew G. Knepley . dim - The spatial dimension 504e2b35d93SBarry Smith . Nc - The number of components 50540d8ff71SMatthew G. Knepley . npoints - The number of quadrature points 50640d8ff71SMatthew G. Knepley . points - The coordinates of each quadrature point 50740d8ff71SMatthew G. Knepley - weights - The weight of each quadrature point 50840d8ff71SMatthew G. Knepley 509c99e0549SMatthew G. Knepley Note: This routine owns the references to points and weights, so they must be allocated using PetscMalloc() and the user should not free them. 510f2fd9e53SMatthew G. Knepley 51140d8ff71SMatthew G. Knepley Level: intermediate 51240d8ff71SMatthew G. Knepley 51340d8ff71SMatthew G. Knepley .seealso: PetscQuadratureCreate(), PetscQuadratureGetData() 51440d8ff71SMatthew G. Knepley @*/ 515a6b92713SMatthew G. Knepley PetscErrorCode PetscQuadratureSetData(PetscQuadrature q, PetscInt dim, PetscInt Nc, PetscInt npoints, const PetscReal points[], const PetscReal weights[]) 51621454ff5SMatthew G. Knepley { 51721454ff5SMatthew G. Knepley PetscFunctionBegin; 5182cd22861SMatthew G. Knepley PetscValidHeaderSpecific(q, PETSCQUADRATURE_CLASSID, 1); 51921454ff5SMatthew G. Knepley if (dim >= 0) q->dim = dim; 520a6b92713SMatthew G. Knepley if (Nc >= 0) q->Nc = Nc; 52121454ff5SMatthew G. Knepley if (npoints >= 0) q->numPoints = npoints; 52221454ff5SMatthew G. Knepley if (points) { 523064a246eSJacob Faibussowitsch PetscValidPointer(points, 5); 52421454ff5SMatthew G. Knepley q->points = points; 52521454ff5SMatthew G. Knepley } 52621454ff5SMatthew G. Knepley if (weights) { 527064a246eSJacob Faibussowitsch PetscValidPointer(weights, 6); 52821454ff5SMatthew G. Knepley q->weights = weights; 52921454ff5SMatthew G. Knepley } 530f9fd7fdbSMatthew G. Knepley PetscFunctionReturn(0); 531f9fd7fdbSMatthew G. Knepley } 532f9fd7fdbSMatthew G. Knepley 533d9bac1caSLisandro Dalcin static PetscErrorCode PetscQuadratureView_Ascii(PetscQuadrature quad, PetscViewer v) 534d9bac1caSLisandro Dalcin { 535d9bac1caSLisandro Dalcin PetscInt q, d, c; 536d9bac1caSLisandro Dalcin PetscViewerFormat format; 537d9bac1caSLisandro Dalcin PetscErrorCode ierr; 538d9bac1caSLisandro Dalcin 539d9bac1caSLisandro Dalcin PetscFunctionBegin; 540c74b4a09SMatthew G. Knepley 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);} 541c74b4a09SMatthew G. Knepley else {ierr = PetscViewerASCIIPrintf(v, "Quadrature of order %D on %D points (dim %D)\n", quad->order, quad->numPoints, quad->dim);CHKERRQ(ierr);} 542d9bac1caSLisandro Dalcin ierr = PetscViewerGetFormat(v, &format);CHKERRQ(ierr); 543d9bac1caSLisandro Dalcin if (format != PETSC_VIEWER_ASCII_INFO_DETAIL) PetscFunctionReturn(0); 544d9bac1caSLisandro Dalcin for (q = 0; q < quad->numPoints; ++q) { 545c74b4a09SMatthew G. Knepley ierr = PetscViewerASCIIPrintf(v, "p%D (", q);CHKERRQ(ierr); 546d9bac1caSLisandro Dalcin ierr = PetscViewerASCIIUseTabs(v, PETSC_FALSE);CHKERRQ(ierr); 547d9bac1caSLisandro Dalcin for (d = 0; d < quad->dim; ++d) { 548d9bac1caSLisandro Dalcin if (d) {ierr = PetscViewerASCIIPrintf(v, ", ");CHKERRQ(ierr);} 549d9bac1caSLisandro Dalcin ierr = PetscViewerASCIIPrintf(v, "%+g", (double)quad->points[q*quad->dim+d]);CHKERRQ(ierr); 550d9bac1caSLisandro Dalcin } 551d9bac1caSLisandro Dalcin ierr = PetscViewerASCIIPrintf(v, ") ");CHKERRQ(ierr); 552c74b4a09SMatthew G. Knepley if (quad->Nc > 1) {ierr = PetscViewerASCIIPrintf(v, "w%D (", q);CHKERRQ(ierr);} 553d9bac1caSLisandro Dalcin for (c = 0; c < quad->Nc; ++c) { 554d9bac1caSLisandro Dalcin if (c) {ierr = PetscViewerASCIIPrintf(v, ", ");CHKERRQ(ierr);} 555c74b4a09SMatthew G. Knepley ierr = PetscViewerASCIIPrintf(v, "%+g", (double)quad->weights[q*quad->Nc+c]);CHKERRQ(ierr); 556d9bac1caSLisandro Dalcin } 557d9bac1caSLisandro Dalcin if (quad->Nc > 1) {ierr = PetscViewerASCIIPrintf(v, ")");CHKERRQ(ierr);} 558d9bac1caSLisandro Dalcin ierr = PetscViewerASCIIPrintf(v, "\n");CHKERRQ(ierr); 559d9bac1caSLisandro Dalcin ierr = PetscViewerASCIIUseTabs(v, PETSC_TRUE);CHKERRQ(ierr); 560d9bac1caSLisandro Dalcin } 561d9bac1caSLisandro Dalcin PetscFunctionReturn(0); 562d9bac1caSLisandro Dalcin } 563d9bac1caSLisandro Dalcin 56440d8ff71SMatthew G. Knepley /*@C 56540d8ff71SMatthew G. Knepley PetscQuadratureView - Views a PetscQuadrature object 56640d8ff71SMatthew G. Knepley 567d083f849SBarry Smith Collective on quad 56840d8ff71SMatthew G. Knepley 56940d8ff71SMatthew G. Knepley Input Parameters: 570d9bac1caSLisandro Dalcin + quad - The PetscQuadrature object 57140d8ff71SMatthew G. Knepley - viewer - The PetscViewer object 57240d8ff71SMatthew G. Knepley 57340d8ff71SMatthew G. Knepley Level: beginner 57440d8ff71SMatthew G. Knepley 57540d8ff71SMatthew G. Knepley .seealso: PetscQuadratureCreate(), PetscQuadratureGetData() 57640d8ff71SMatthew G. Knepley @*/ 577f9fd7fdbSMatthew G. Knepley PetscErrorCode PetscQuadratureView(PetscQuadrature quad, PetscViewer viewer) 578f9fd7fdbSMatthew G. Knepley { 579d9bac1caSLisandro Dalcin PetscBool iascii; 580f9fd7fdbSMatthew G. Knepley PetscErrorCode ierr; 581f9fd7fdbSMatthew G. Knepley 582f9fd7fdbSMatthew G. Knepley PetscFunctionBegin; 583d9bac1caSLisandro Dalcin PetscValidHeader(quad, 1); 584d9bac1caSLisandro Dalcin if (viewer) PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 585d9bac1caSLisandro Dalcin if (!viewer) {ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject) quad), &viewer);CHKERRQ(ierr);} 586d9bac1caSLisandro Dalcin ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr); 587d9bac1caSLisandro Dalcin ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 588d9bac1caSLisandro Dalcin if (iascii) {ierr = PetscQuadratureView_Ascii(quad, viewer);CHKERRQ(ierr);} 589d9bac1caSLisandro Dalcin ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 590bfa639d9SMatthew G. Knepley PetscFunctionReturn(0); 591bfa639d9SMatthew G. Knepley } 592bfa639d9SMatthew G. Knepley 59389710940SMatthew G. Knepley /*@C 59489710940SMatthew G. Knepley PetscQuadratureExpandComposite - Return a quadrature over the composite element, which has the original quadrature in each subelement 59589710940SMatthew G. Knepley 59689710940SMatthew G. Knepley Not collective 59789710940SMatthew G. Knepley 598d8d19677SJose E. Roman Input Parameters: 59989710940SMatthew G. Knepley + q - The original PetscQuadrature 60089710940SMatthew G. Knepley . numSubelements - The number of subelements the original element is divided into 60189710940SMatthew G. Knepley . v0 - An array of the initial points for each subelement 60289710940SMatthew G. Knepley - jac - An array of the Jacobian mappings from the reference to each subelement 60389710940SMatthew G. Knepley 60489710940SMatthew G. Knepley Output Parameters: 60589710940SMatthew G. Knepley . dim - The dimension 60689710940SMatthew G. Knepley 60789710940SMatthew G. Knepley Note: Together v0 and jac define an affine mapping from the original reference element to each subelement 60889710940SMatthew G. Knepley 609f5f57ec0SBarry Smith Not available from Fortran 610f5f57ec0SBarry Smith 61189710940SMatthew G. Knepley Level: intermediate 61289710940SMatthew G. Knepley 61389710940SMatthew G. Knepley .seealso: PetscFECreate(), PetscSpaceGetDimension(), PetscDualSpaceGetDimension() 61489710940SMatthew G. Knepley @*/ 61589710940SMatthew G. Knepley PetscErrorCode PetscQuadratureExpandComposite(PetscQuadrature q, PetscInt numSubelements, const PetscReal v0[], const PetscReal jac[], PetscQuadrature *qref) 61689710940SMatthew G. Knepley { 61789710940SMatthew G. Knepley const PetscReal *points, *weights; 61889710940SMatthew G. Knepley PetscReal *pointsRef, *weightsRef; 619a6b92713SMatthew G. Knepley PetscInt dim, Nc, order, npoints, npointsRef, c, p, cp, d, e; 62089710940SMatthew G. Knepley PetscErrorCode ierr; 62189710940SMatthew G. Knepley 62289710940SMatthew G. Knepley PetscFunctionBegin; 6232cd22861SMatthew G. Knepley PetscValidHeaderSpecific(q, PETSCQUADRATURE_CLASSID, 1); 62489710940SMatthew G. Knepley PetscValidPointer(v0, 3); 62589710940SMatthew G. Knepley PetscValidPointer(jac, 4); 62689710940SMatthew G. Knepley PetscValidPointer(qref, 5); 62789710940SMatthew G. Knepley ierr = PetscQuadratureCreate(PETSC_COMM_SELF, qref);CHKERRQ(ierr); 62889710940SMatthew G. Knepley ierr = PetscQuadratureGetOrder(q, &order);CHKERRQ(ierr); 629a6b92713SMatthew G. Knepley ierr = PetscQuadratureGetData(q, &dim, &Nc, &npoints, &points, &weights);CHKERRQ(ierr); 63089710940SMatthew G. Knepley npointsRef = npoints*numSubelements; 63189710940SMatthew G. Knepley ierr = PetscMalloc1(npointsRef*dim,&pointsRef);CHKERRQ(ierr); 632a6b92713SMatthew G. Knepley ierr = PetscMalloc1(npointsRef*Nc, &weightsRef);CHKERRQ(ierr); 63389710940SMatthew G. Knepley for (c = 0; c < numSubelements; ++c) { 63489710940SMatthew G. Knepley for (p = 0; p < npoints; ++p) { 63589710940SMatthew G. Knepley for (d = 0; d < dim; ++d) { 63689710940SMatthew G. Knepley pointsRef[(c*npoints + p)*dim+d] = v0[c*dim+d]; 63789710940SMatthew G. Knepley for (e = 0; e < dim; ++e) { 63889710940SMatthew G. Knepley pointsRef[(c*npoints + p)*dim+d] += jac[(c*dim + d)*dim+e]*(points[p*dim+e] + 1.0); 63989710940SMatthew G. Knepley } 64089710940SMatthew G. Knepley } 64189710940SMatthew G. Knepley /* Could also use detJ here */ 642a6b92713SMatthew G. Knepley for (cp = 0; cp < Nc; ++cp) weightsRef[(c*npoints+p)*Nc+cp] = weights[p*Nc+cp]/numSubelements; 64389710940SMatthew G. Knepley } 64489710940SMatthew G. Knepley } 64589710940SMatthew G. Knepley ierr = PetscQuadratureSetOrder(*qref, order);CHKERRQ(ierr); 646a6b92713SMatthew G. Knepley ierr = PetscQuadratureSetData(*qref, dim, Nc, npointsRef, pointsRef, weightsRef);CHKERRQ(ierr); 64789710940SMatthew G. Knepley PetscFunctionReturn(0); 64889710940SMatthew G. Knepley } 64989710940SMatthew G. Knepley 65094e21283SToby Isaac /* Compute the coefficients for the Jacobi polynomial recurrence, 65194e21283SToby Isaac * 65294e21283SToby Isaac * J^{a,b}_n(x) = (cnm1 + cnm1x * x) * J^{a,b}_{n-1}(x) - cnm2 * J^{a,b}_{n-2}(x). 65394e21283SToby Isaac */ 65494e21283SToby Isaac #define PetscDTJacobiRecurrence_Internal(n,a,b,cnm1,cnm1x,cnm2) \ 65594e21283SToby Isaac do { \ 65694e21283SToby Isaac PetscReal _a = (a); \ 65794e21283SToby Isaac PetscReal _b = (b); \ 65894e21283SToby Isaac PetscReal _n = (n); \ 65994e21283SToby Isaac if (n == 1) { \ 66094e21283SToby Isaac (cnm1) = (_a-_b) * 0.5; \ 66194e21283SToby Isaac (cnm1x) = (_a+_b+2.)*0.5; \ 66294e21283SToby Isaac (cnm2) = 0.; \ 66394e21283SToby Isaac } else { \ 66494e21283SToby Isaac PetscReal _2n = _n+_n; \ 66594e21283SToby Isaac PetscReal _d = (_2n*(_n+_a+_b)*(_2n+_a+_b-2)); \ 66694e21283SToby Isaac PetscReal _n1 = (_2n+_a+_b-1.)*(_a*_a-_b*_b); \ 66794e21283SToby Isaac PetscReal _n1x = (_2n+_a+_b-1.)*(_2n+_a+_b)*(_2n+_a+_b-2); \ 66894e21283SToby Isaac PetscReal _n2 = 2.*((_n+_a-1.)*(_n+_b-1.)*(_2n+_a+_b)); \ 66994e21283SToby Isaac (cnm1) = _n1 / _d; \ 67094e21283SToby Isaac (cnm1x) = _n1x / _d; \ 67194e21283SToby Isaac (cnm2) = _n2 / _d; \ 67294e21283SToby Isaac } \ 67394e21283SToby Isaac } while (0) 67494e21283SToby Isaac 675fbdc3dfeSToby Isaac /*@ 676fbdc3dfeSToby Isaac PetscDTJacobiNorm - Compute the weighted L2 norm of a Jacobi polynomial. 677fbdc3dfeSToby Isaac 678fbdc3dfeSToby Isaac $\| P^{\alpha,\beta}_n \|_{\alpha,\beta}^2 = \int_{-1}^1 (1 + x)^{\alpha} (1 - x)^{\beta} P^{\alpha,\beta}_n (x)^2 dx.$ 679fbdc3dfeSToby Isaac 6804165533cSJose E. Roman Input Parameters: 681fbdc3dfeSToby Isaac - alpha - the left exponent > -1 682fbdc3dfeSToby Isaac . beta - the right exponent > -1 683fbdc3dfeSToby Isaac + n - the polynomial degree 684fbdc3dfeSToby Isaac 6854165533cSJose E. Roman Output Parameter: 686fbdc3dfeSToby Isaac . norm - the weighted L2 norm 687fbdc3dfeSToby Isaac 688fbdc3dfeSToby Isaac Level: beginner 689fbdc3dfeSToby Isaac 690fbdc3dfeSToby Isaac .seealso: PetscDTJacobiEval() 691fbdc3dfeSToby Isaac @*/ 692fbdc3dfeSToby Isaac PetscErrorCode PetscDTJacobiNorm(PetscReal alpha, PetscReal beta, PetscInt n, PetscReal *norm) 693fbdc3dfeSToby Isaac { 694fbdc3dfeSToby Isaac PetscReal twoab1; 695fbdc3dfeSToby Isaac PetscReal gr; 696fbdc3dfeSToby Isaac 697fbdc3dfeSToby Isaac PetscFunctionBegin; 6982c71b3e2SJacob Faibussowitsch PetscCheckFalse(alpha <= -1.,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Exponent alpha %g <= -1. invalid", (double) alpha); 6992c71b3e2SJacob Faibussowitsch PetscCheckFalse(beta <= -1.,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Exponent beta %g <= -1. invalid", (double) beta); 7002c71b3e2SJacob Faibussowitsch PetscCheckFalse(n < 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "n %D < 0 invalid", n); 701fbdc3dfeSToby Isaac twoab1 = PetscPowReal(2., alpha + beta + 1.); 702fbdc3dfeSToby Isaac #if defined(PETSC_HAVE_LGAMMA) 703fbdc3dfeSToby Isaac if (!n) { 704fbdc3dfeSToby Isaac gr = PetscExpReal(PetscLGamma(alpha+1.) + PetscLGamma(beta+1.) - PetscLGamma(alpha+beta+2.)); 705fbdc3dfeSToby Isaac } else { 706fbdc3dfeSToby Isaac gr = PetscExpReal(PetscLGamma(n+alpha+1.) + PetscLGamma(n+beta+1.) - (PetscLGamma(n+1.) + PetscLGamma(n+alpha+beta+1.))) / (n+n+alpha+beta+1.); 707fbdc3dfeSToby Isaac } 708fbdc3dfeSToby Isaac #else 709fbdc3dfeSToby Isaac { 710fbdc3dfeSToby Isaac PetscInt alphai = (PetscInt) alpha; 711fbdc3dfeSToby Isaac PetscInt betai = (PetscInt) beta; 712fbdc3dfeSToby Isaac PetscInt i; 713fbdc3dfeSToby Isaac 714fbdc3dfeSToby Isaac gr = n ? (1. / (n+n+alpha+beta+1.)) : 1.; 715fbdc3dfeSToby Isaac if ((PetscReal) alphai == alpha) { 716fbdc3dfeSToby Isaac if (!n) { 717fbdc3dfeSToby Isaac for (i = 0; i < alphai; i++) gr *= (i+1.) / (beta+i+1.); 718fbdc3dfeSToby Isaac gr /= (alpha+beta+1.); 719fbdc3dfeSToby Isaac } else { 720fbdc3dfeSToby Isaac for (i = 0; i < alphai; i++) gr *= (n+i+1.) / (n+beta+i+1.); 721fbdc3dfeSToby Isaac } 722fbdc3dfeSToby Isaac } else if ((PetscReal) betai == beta) { 723fbdc3dfeSToby Isaac if (!n) { 724fbdc3dfeSToby Isaac for (i = 0; i < betai; i++) gr *= (i+1.) / (alpha+i+2.); 725fbdc3dfeSToby Isaac gr /= (alpha+beta+1.); 726fbdc3dfeSToby Isaac } else { 727fbdc3dfeSToby Isaac for (i = 0; i < betai; i++) gr *= (n+i+1.) / (n+alpha+i+1.); 728fbdc3dfeSToby Isaac } 729fbdc3dfeSToby Isaac } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"lgamma() - math routine is unavailable."); 730fbdc3dfeSToby Isaac } 731fbdc3dfeSToby Isaac #endif 732fbdc3dfeSToby Isaac *norm = PetscSqrtReal(twoab1 * gr); 733fbdc3dfeSToby Isaac PetscFunctionReturn(0); 734fbdc3dfeSToby Isaac } 735fbdc3dfeSToby Isaac 73694e21283SToby Isaac static PetscErrorCode PetscDTJacobiEval_Internal(PetscInt npoints, PetscReal a, PetscReal b, PetscInt k, const PetscReal *points, PetscInt ndegree, const PetscInt *degrees, PetscReal *p) 73794e21283SToby Isaac { 73894e21283SToby Isaac PetscReal ak, bk; 73994e21283SToby Isaac PetscReal abk1; 74094e21283SToby Isaac PetscInt i,l,maxdegree; 74194e21283SToby Isaac 74294e21283SToby Isaac PetscFunctionBegin; 74394e21283SToby Isaac maxdegree = degrees[ndegree-1] - k; 74494e21283SToby Isaac ak = a + k; 74594e21283SToby Isaac bk = b + k; 74694e21283SToby Isaac abk1 = a + b + k + 1.; 74794e21283SToby Isaac if (maxdegree < 0) { 74894e21283SToby Isaac for (i = 0; i < npoints; i++) for (l = 0; l < ndegree; l++) p[i*ndegree+l] = 0.; 74994e21283SToby Isaac PetscFunctionReturn(0); 75094e21283SToby Isaac } 75194e21283SToby Isaac for (i=0; i<npoints; i++) { 75294e21283SToby Isaac PetscReal pm1,pm2,x; 75394e21283SToby Isaac PetscReal cnm1, cnm1x, cnm2; 75494e21283SToby Isaac PetscInt j,m; 75594e21283SToby Isaac 75694e21283SToby Isaac x = points[i]; 75794e21283SToby Isaac pm2 = 1.; 75894e21283SToby Isaac PetscDTJacobiRecurrence_Internal(1,ak,bk,cnm1,cnm1x,cnm2); 75994e21283SToby Isaac pm1 = (cnm1 + cnm1x*x); 76094e21283SToby Isaac l = 0; 76194e21283SToby Isaac while (l < ndegree && degrees[l] - k < 0) { 76294e21283SToby Isaac p[l++] = 0.; 76394e21283SToby Isaac } 76494e21283SToby Isaac while (l < ndegree && degrees[l] - k == 0) { 76594e21283SToby Isaac p[l] = pm2; 76694e21283SToby Isaac for (m = 0; m < k; m++) p[l] *= (abk1 + m) * 0.5; 76794e21283SToby Isaac l++; 76894e21283SToby Isaac } 76994e21283SToby Isaac while (l < ndegree && degrees[l] - k == 1) { 77094e21283SToby Isaac p[l] = pm1; 77194e21283SToby Isaac for (m = 0; m < k; m++) p[l] *= (abk1 + 1 + m) * 0.5; 77294e21283SToby Isaac l++; 77394e21283SToby Isaac } 77494e21283SToby Isaac for (j=2; j<=maxdegree; j++) { 77594e21283SToby Isaac PetscReal pp; 77694e21283SToby Isaac 77794e21283SToby Isaac PetscDTJacobiRecurrence_Internal(j,ak,bk,cnm1,cnm1x,cnm2); 77894e21283SToby Isaac pp = (cnm1 + cnm1x*x)*pm1 - cnm2*pm2; 77994e21283SToby Isaac pm2 = pm1; 78094e21283SToby Isaac pm1 = pp; 78194e21283SToby Isaac while (l < ndegree && degrees[l] - k == j) { 78294e21283SToby Isaac p[l] = pp; 78394e21283SToby Isaac for (m = 0; m < k; m++) p[l] *= (abk1 + j + m) * 0.5; 78494e21283SToby Isaac l++; 78594e21283SToby Isaac } 78694e21283SToby Isaac } 78794e21283SToby Isaac p += ndegree; 78894e21283SToby Isaac } 78994e21283SToby Isaac PetscFunctionReturn(0); 79094e21283SToby Isaac } 79194e21283SToby Isaac 79237045ce4SJed Brown /*@ 793fbdc3dfeSToby Isaac PetscDTJacobiEvalJet - Evaluate the jet (function and derivatives) of the Jacobi polynomials basis up to a given degree. The Jacobi polynomials with indices $\alpha$ and $\beta$ are orthogonal with respect to the weighted inner product $\langle f, g \rangle = \int_{-1}^1 (1+x)^{\alpha} (1-x)^{\beta) f(x) g(x) dx$. 794fbdc3dfeSToby Isaac 7954165533cSJose E. Roman Input Parameters: 796fbdc3dfeSToby Isaac + alpha - the left exponent of the weight 797fbdc3dfeSToby Isaac . beta - the right exponetn of the weight 798fbdc3dfeSToby Isaac . npoints - the number of points to evaluate the polynomials at 799fbdc3dfeSToby Isaac . points - [npoints] array of point coordinates 800fbdc3dfeSToby Isaac . degree - the maximm degree polynomial space to evaluate, (degree + 1) will be evaluated total. 801fbdc3dfeSToby Isaac - k - the maximum derivative to evaluate in the jet, (k + 1) will be evaluated total. 802fbdc3dfeSToby Isaac 803fbdc3dfeSToby Isaac Output Argments: 804fbdc3dfeSToby Isaac - p - an array containing the evaluations of the Jacobi polynomials's jets on the points. the size is (degree + 1) x 805fbdc3dfeSToby Isaac (k + 1) x npoints, which also describes the order of the dimensions of this three-dimensional array: the first 806fbdc3dfeSToby Isaac (slowest varying) dimension is polynomial degree; the second dimension is derivative order; the third (fastest 807fbdc3dfeSToby Isaac varying) dimension is the index of the evaluation point. 808fbdc3dfeSToby Isaac 809fbdc3dfeSToby Isaac Level: advanced 810fbdc3dfeSToby Isaac 811fbdc3dfeSToby Isaac .seealso: PetscDTJacobiEval(), PetscDTPKDEvalJet() 812fbdc3dfeSToby Isaac @*/ 813fbdc3dfeSToby Isaac PetscErrorCode PetscDTJacobiEvalJet(PetscReal alpha, PetscReal beta, PetscInt npoints, const PetscReal points[], PetscInt degree, PetscInt k, PetscReal p[]) 814fbdc3dfeSToby Isaac { 815fbdc3dfeSToby Isaac PetscInt i, j, l; 816fbdc3dfeSToby Isaac PetscInt *degrees; 817fbdc3dfeSToby Isaac PetscReal *psingle; 818fbdc3dfeSToby Isaac PetscErrorCode ierr; 819fbdc3dfeSToby Isaac 820fbdc3dfeSToby Isaac PetscFunctionBegin; 821fbdc3dfeSToby Isaac if (degree == 0) { 822fbdc3dfeSToby Isaac PetscInt zero = 0; 823fbdc3dfeSToby Isaac 824fbdc3dfeSToby Isaac for (i = 0; i <= k; i++) { 825fbdc3dfeSToby Isaac ierr = PetscDTJacobiEval_Internal(npoints, alpha, beta, i, points, 1, &zero, &p[i*npoints]);CHKERRQ(ierr); 826fbdc3dfeSToby Isaac } 827fbdc3dfeSToby Isaac PetscFunctionReturn(0); 828fbdc3dfeSToby Isaac } 829fbdc3dfeSToby Isaac ierr = PetscMalloc1(degree + 1, °rees);CHKERRQ(ierr); 830fbdc3dfeSToby Isaac ierr = PetscMalloc1((degree + 1) * npoints, &psingle);CHKERRQ(ierr); 831fbdc3dfeSToby Isaac for (i = 0; i <= degree; i++) degrees[i] = i; 832fbdc3dfeSToby Isaac for (i = 0; i <= k; i++) { 833fbdc3dfeSToby Isaac ierr = PetscDTJacobiEval_Internal(npoints, alpha, beta, i, points, degree + 1, degrees, psingle);CHKERRQ(ierr); 834fbdc3dfeSToby Isaac for (j = 0; j <= degree; j++) { 835fbdc3dfeSToby Isaac for (l = 0; l < npoints; l++) { 836fbdc3dfeSToby Isaac p[(j * (k + 1) + i) * npoints + l] = psingle[l * (degree + 1) + j]; 837fbdc3dfeSToby Isaac } 838fbdc3dfeSToby Isaac } 839fbdc3dfeSToby Isaac } 840fbdc3dfeSToby Isaac ierr = PetscFree(psingle);CHKERRQ(ierr); 841fbdc3dfeSToby Isaac ierr = PetscFree(degrees);CHKERRQ(ierr); 842fbdc3dfeSToby Isaac PetscFunctionReturn(0); 843fbdc3dfeSToby Isaac } 844fbdc3dfeSToby Isaac 845fbdc3dfeSToby Isaac /*@ 84694e21283SToby Isaac PetscDTJacobiEval - evaluate Jacobi polynomials for the weight function $(1.+x)^{\alpha} (1.-x)^{\beta}$ 84794e21283SToby Isaac at points 84894e21283SToby Isaac 84994e21283SToby Isaac Not Collective 85094e21283SToby Isaac 8514165533cSJose E. Roman Input Parameters: 85294e21283SToby Isaac + npoints - number of spatial points to evaluate at 85394e21283SToby Isaac . alpha - the left exponent > -1 85494e21283SToby Isaac . beta - the right exponent > -1 85594e21283SToby Isaac . points - array of locations to evaluate at 85694e21283SToby Isaac . ndegree - number of basis degrees to evaluate 85794e21283SToby Isaac - degrees - sorted array of degrees to evaluate 85894e21283SToby Isaac 8594165533cSJose E. Roman Output Parameters: 86094e21283SToby Isaac + B - row-oriented basis evaluation matrix B[point*ndegree + degree] (dimension npoints*ndegrees, allocated by caller) (or NULL) 86194e21283SToby Isaac . D - row-oriented derivative evaluation matrix (or NULL) 86294e21283SToby Isaac - D2 - row-oriented second derivative evaluation matrix (or NULL) 86394e21283SToby Isaac 86494e21283SToby Isaac Level: intermediate 86594e21283SToby Isaac 86694e21283SToby Isaac .seealso: PetscDTGaussQuadrature() 86794e21283SToby Isaac @*/ 86894e21283SToby Isaac PetscErrorCode PetscDTJacobiEval(PetscInt npoints,PetscReal alpha, PetscReal beta, const PetscReal *points,PetscInt ndegree,const PetscInt *degrees,PetscReal *B,PetscReal *D,PetscReal *D2) 86994e21283SToby Isaac { 87094e21283SToby Isaac PetscErrorCode ierr; 87194e21283SToby Isaac 87294e21283SToby Isaac PetscFunctionBegin; 8732c71b3e2SJacob Faibussowitsch PetscCheckFalse(alpha <= -1.,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"alpha must be > -1."); 8742c71b3e2SJacob Faibussowitsch PetscCheckFalse(beta <= -1.,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"beta must be > -1."); 87594e21283SToby Isaac if (!npoints || !ndegree) PetscFunctionReturn(0); 87694e21283SToby Isaac if (B) {ierr = PetscDTJacobiEval_Internal(npoints, alpha, beta, 0, points, ndegree, degrees, B);CHKERRQ(ierr);} 87794e21283SToby Isaac if (D) {ierr = PetscDTJacobiEval_Internal(npoints, alpha, beta, 1, points, ndegree, degrees, D);CHKERRQ(ierr);} 87894e21283SToby Isaac if (D2) {ierr = PetscDTJacobiEval_Internal(npoints, alpha, beta, 2, points, ndegree, degrees, D2);CHKERRQ(ierr);} 87994e21283SToby Isaac PetscFunctionReturn(0); 88094e21283SToby Isaac } 88194e21283SToby Isaac 88294e21283SToby Isaac /*@ 88394e21283SToby Isaac PetscDTLegendreEval - evaluate Legendre polynomials at points 88437045ce4SJed Brown 88537045ce4SJed Brown Not Collective 88637045ce4SJed Brown 8874165533cSJose E. Roman Input Parameters: 88837045ce4SJed Brown + npoints - number of spatial points to evaluate at 88937045ce4SJed Brown . points - array of locations to evaluate at 89037045ce4SJed Brown . ndegree - number of basis degrees to evaluate 89137045ce4SJed Brown - degrees - sorted array of degrees to evaluate 89237045ce4SJed Brown 8934165533cSJose E. Roman Output Parameters: 8940298fd71SBarry Smith + B - row-oriented basis evaluation matrix B[point*ndegree + degree] (dimension npoints*ndegrees, allocated by caller) (or NULL) 8950298fd71SBarry Smith . D - row-oriented derivative evaluation matrix (or NULL) 8960298fd71SBarry Smith - D2 - row-oriented second derivative evaluation matrix (or NULL) 89737045ce4SJed Brown 89837045ce4SJed Brown Level: intermediate 89937045ce4SJed Brown 90037045ce4SJed Brown .seealso: PetscDTGaussQuadrature() 90137045ce4SJed Brown @*/ 90237045ce4SJed Brown PetscErrorCode PetscDTLegendreEval(PetscInt npoints,const PetscReal *points,PetscInt ndegree,const PetscInt *degrees,PetscReal *B,PetscReal *D,PetscReal *D2) 90337045ce4SJed Brown { 90494e21283SToby Isaac PetscErrorCode ierr; 90537045ce4SJed Brown 90637045ce4SJed Brown PetscFunctionBegin; 90794e21283SToby Isaac ierr = PetscDTJacobiEval(npoints, 0., 0., points, ndegree, degrees, B, D, D2);CHKERRQ(ierr); 90837045ce4SJed Brown PetscFunctionReturn(0); 90937045ce4SJed Brown } 91037045ce4SJed Brown 911fbdc3dfeSToby Isaac /*@ 912fbdc3dfeSToby Isaac PetscDTIndexToGradedOrder - convert an index into a tuple of monomial degrees in a graded order (that is, if the degree sum of tuple x is less than the degree sum of tuple y, then the index of x is smaller than the index of y) 913fbdc3dfeSToby Isaac 914fbdc3dfeSToby Isaac Input Parameters: 915fbdc3dfeSToby Isaac + len - the desired length of the degree tuple 916fbdc3dfeSToby Isaac - index - the index to convert: should be >= 0 917fbdc3dfeSToby Isaac 918fbdc3dfeSToby Isaac Output Parameter: 919fbdc3dfeSToby Isaac . degtup - will be filled with a tuple of degrees 920fbdc3dfeSToby Isaac 921fbdc3dfeSToby Isaac Level: beginner 922fbdc3dfeSToby Isaac 923fbdc3dfeSToby Isaac Note: for two tuples x and y with the same degree sum, partial degree sums over the final elements of the tuples 924fbdc3dfeSToby Isaac acts as a tiebreaker. For example, (2, 1, 1) and (1, 2, 1) have the same degree sum, but the degree sum over the 925fbdc3dfeSToby Isaac last two elements is smaller for the former, so (2, 1, 1) < (1, 2, 1). 926fbdc3dfeSToby Isaac 927fbdc3dfeSToby Isaac .seealso: PetscDTGradedOrderToIndex() 928fbdc3dfeSToby Isaac @*/ 929fbdc3dfeSToby Isaac PetscErrorCode PetscDTIndexToGradedOrder(PetscInt len, PetscInt index, PetscInt degtup[]) 930fbdc3dfeSToby Isaac { 931fbdc3dfeSToby Isaac PetscInt i, total; 932fbdc3dfeSToby Isaac PetscInt sum; 933fbdc3dfeSToby Isaac 934fbdc3dfeSToby Isaac PetscFunctionBeginHot; 9352c71b3e2SJacob Faibussowitsch PetscCheckFalse(len < 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "length must be non-negative"); 9362c71b3e2SJacob Faibussowitsch PetscCheckFalse(index < 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "index must be non-negative"); 937fbdc3dfeSToby Isaac total = 1; 938fbdc3dfeSToby Isaac sum = 0; 939fbdc3dfeSToby Isaac while (index >= total) { 940fbdc3dfeSToby Isaac index -= total; 941fbdc3dfeSToby Isaac total = (total * (len + sum)) / (sum + 1); 942fbdc3dfeSToby Isaac sum++; 943fbdc3dfeSToby Isaac } 944fbdc3dfeSToby Isaac for (i = 0; i < len; i++) { 945fbdc3dfeSToby Isaac PetscInt c; 946fbdc3dfeSToby Isaac 947fbdc3dfeSToby Isaac degtup[i] = sum; 948fbdc3dfeSToby Isaac for (c = 0, total = 1; c < sum; c++) { 949fbdc3dfeSToby Isaac /* going into the loop, total is the number of way to have a tuple of sum exactly c with length len - 1 - i */ 950fbdc3dfeSToby Isaac if (index < total) break; 951fbdc3dfeSToby Isaac index -= total; 952fbdc3dfeSToby Isaac total = (total * (len - 1 - i + c)) / (c + 1); 953fbdc3dfeSToby Isaac degtup[i]--; 954fbdc3dfeSToby Isaac } 955fbdc3dfeSToby Isaac sum -= degtup[i]; 956fbdc3dfeSToby Isaac } 957fbdc3dfeSToby Isaac PetscFunctionReturn(0); 958fbdc3dfeSToby Isaac } 959fbdc3dfeSToby Isaac 960fbdc3dfeSToby Isaac /*@ 961fbdc3dfeSToby Isaac PetscDTGradedOrderToIndex - convert a tuple into an index in a graded order, the inverse of PetscDTIndexToGradedOrder(). 962fbdc3dfeSToby Isaac 963fbdc3dfeSToby Isaac Input Parameters: 964fbdc3dfeSToby Isaac + len - the length of the degree tuple 965fbdc3dfeSToby Isaac - degtup - tuple with this length 966fbdc3dfeSToby Isaac 967fbdc3dfeSToby Isaac Output Parameter: 968fbdc3dfeSToby Isaac . index - index in graded order: >= 0 969fbdc3dfeSToby Isaac 970fbdc3dfeSToby Isaac Level: Beginner 971fbdc3dfeSToby Isaac 972fbdc3dfeSToby Isaac Note: for two tuples x and y with the same degree sum, partial degree sums over the final elements of the tuples 973fbdc3dfeSToby Isaac acts as a tiebreaker. For example, (2, 1, 1) and (1, 2, 1) have the same degree sum, but the degree sum over the 974fbdc3dfeSToby Isaac last two elements is smaller for the former, so (2, 1, 1) < (1, 2, 1). 975fbdc3dfeSToby Isaac 976fbdc3dfeSToby Isaac .seealso: PetscDTIndexToGradedOrder() 977fbdc3dfeSToby Isaac @*/ 978fbdc3dfeSToby Isaac PetscErrorCode PetscDTGradedOrderToIndex(PetscInt len, const PetscInt degtup[], PetscInt *index) 979fbdc3dfeSToby Isaac { 980fbdc3dfeSToby Isaac PetscInt i, idx, sum, total; 981fbdc3dfeSToby Isaac 982fbdc3dfeSToby Isaac PetscFunctionBeginHot; 9832c71b3e2SJacob Faibussowitsch PetscCheckFalse(len < 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "length must be non-negative"); 984fbdc3dfeSToby Isaac for (i = 0, sum = 0; i < len; i++) sum += degtup[i]; 985fbdc3dfeSToby Isaac idx = 0; 986fbdc3dfeSToby Isaac total = 1; 987fbdc3dfeSToby Isaac for (i = 0; i < sum; i++) { 988fbdc3dfeSToby Isaac idx += total; 989fbdc3dfeSToby Isaac total = (total * (len + i)) / (i + 1); 990fbdc3dfeSToby Isaac } 991fbdc3dfeSToby Isaac for (i = 0; i < len - 1; i++) { 992fbdc3dfeSToby Isaac PetscInt c; 993fbdc3dfeSToby Isaac 994fbdc3dfeSToby Isaac total = 1; 995fbdc3dfeSToby Isaac sum -= degtup[i]; 996fbdc3dfeSToby Isaac for (c = 0; c < sum; c++) { 997fbdc3dfeSToby Isaac idx += total; 998fbdc3dfeSToby Isaac total = (total * (len - 1 - i + c)) / (c + 1); 999fbdc3dfeSToby Isaac } 1000fbdc3dfeSToby Isaac } 1001fbdc3dfeSToby Isaac *index = idx; 1002fbdc3dfeSToby Isaac PetscFunctionReturn(0); 1003fbdc3dfeSToby Isaac } 1004fbdc3dfeSToby Isaac 1005e3aa2e09SToby Isaac static PetscBool PKDCite = PETSC_FALSE; 1006e3aa2e09SToby Isaac const char PKDCitation[] = "@article{Kirby2010,\n" 1007e3aa2e09SToby Isaac " title={Singularity-free evaluation of collapsed-coordinate orthogonal polynomials},\n" 1008e3aa2e09SToby Isaac " author={Kirby, Robert C},\n" 1009e3aa2e09SToby Isaac " journal={ACM Transactions on Mathematical Software (TOMS)},\n" 1010e3aa2e09SToby Isaac " volume={37},\n" 1011e3aa2e09SToby Isaac " number={1},\n" 1012e3aa2e09SToby Isaac " pages={1--16},\n" 1013e3aa2e09SToby Isaac " year={2010},\n" 1014e3aa2e09SToby Isaac " publisher={ACM New York, NY, USA}\n}\n"; 1015e3aa2e09SToby Isaac 1016fbdc3dfeSToby Isaac /*@ 1017d8f25ad8SToby Isaac PetscDTPKDEvalJet - Evaluate the jet (function and derivatives) of the Proriol-Koornwinder-Dubiner (PKD) basis for 1018fbdc3dfeSToby Isaac the space of polynomials up to a given degree. The PKD basis is L2-orthonormal on the biunit simplex (which is used 1019fbdc3dfeSToby Isaac as the reference element for finite elements in PETSc), which makes it a stable basis to use for evaluating 1020fbdc3dfeSToby Isaac polynomials in that domain. 1021fbdc3dfeSToby Isaac 10224165533cSJose E. Roman Input Parameters: 1023fbdc3dfeSToby Isaac + dim - the number of variables in the multivariate polynomials 1024fbdc3dfeSToby Isaac . npoints - the number of points to evaluate the polynomials at 1025fbdc3dfeSToby Isaac . points - [npoints x dim] array of point coordinates 1026fbdc3dfeSToby Isaac . degree - the degree (sum of degrees on the variables in a monomial) of the polynomial space to evaluate. There are ((dim + degree) choose dim) polynomials in this space. 1027fbdc3dfeSToby Isaac - k - the maximum order partial derivative to evaluate in the jet. There are (dim + k choose dim) partial derivatives 1028fbdc3dfeSToby Isaac in the jet. Choosing k = 0 means to evaluate just the function and no derivatives 1029fbdc3dfeSToby Isaac 1030fbdc3dfeSToby Isaac Output Argments: 1031fbdc3dfeSToby Isaac - p - an array containing the evaluations of the PKD polynomials' jets on the points. The size is ((dim + degree) 1032fbdc3dfeSToby Isaac choose dim) x ((dim + k) choose dim) x npoints, which also describes the order of the dimensions of this 1033fbdc3dfeSToby Isaac three-dimensional array: the first (slowest varying) dimension is basis function index; the second dimension is jet 1034fbdc3dfeSToby Isaac index; the third (fastest varying) dimension is the index of the evaluation point. 1035fbdc3dfeSToby Isaac 1036fbdc3dfeSToby Isaac Level: advanced 1037fbdc3dfeSToby Isaac 1038fbdc3dfeSToby Isaac Note: The ordering of the basis functions, and the ordering of the derivatives in the jet, both follow the graded 1039fbdc3dfeSToby Isaac ordering of PetscDTIndexToGradedOrder() and PetscDTGradedOrderToIndex(). For example, in 3D, the polynomial with 1040d8f25ad8SToby Isaac leading monomial x^2,y^0,z^1, which has degree tuple (2,0,1), which by PetscDTGradedOrderToIndex() has index 12 (it is the 13th basis function in the space); 1041fbdc3dfeSToby Isaac the partial derivative $\partial_x \partial_z$ has order tuple (1,0,1), appears at index 6 in the jet (it is the 7th partial derivative in the jet). 1042fbdc3dfeSToby Isaac 1043e3aa2e09SToby Isaac The implementation uses Kirby's singularity-free evaluation algorithm, https://doi.org/10.1145/1644001.1644006. 1044e3aa2e09SToby Isaac 1045fbdc3dfeSToby Isaac .seealso: PetscDTGradedOrderToIndex(), PetscDTIndexToGradedOrder(), PetscDTJacobiEvalJet() 1046fbdc3dfeSToby Isaac @*/ 1047fbdc3dfeSToby Isaac PetscErrorCode PetscDTPKDEvalJet(PetscInt dim, PetscInt npoints, const PetscReal points[], PetscInt degree, PetscInt k, PetscReal p[]) 1048fbdc3dfeSToby Isaac { 1049fbdc3dfeSToby Isaac PetscInt degidx, kidx, d, pt; 1050fbdc3dfeSToby Isaac PetscInt Nk, Ndeg; 1051fbdc3dfeSToby Isaac PetscInt *ktup, *degtup; 1052fbdc3dfeSToby Isaac PetscReal *scales, initscale, scaleexp; 1053fbdc3dfeSToby Isaac PetscErrorCode ierr; 1054fbdc3dfeSToby Isaac 1055fbdc3dfeSToby Isaac PetscFunctionBegin; 1056e3aa2e09SToby Isaac ierr = PetscCitationsRegister(PKDCitation, &PKDCite);CHKERRQ(ierr); 1057fbdc3dfeSToby Isaac ierr = PetscDTBinomialInt(dim + k, k, &Nk);CHKERRQ(ierr); 1058fbdc3dfeSToby Isaac ierr = PetscDTBinomialInt(degree + dim, degree, &Ndeg);CHKERRQ(ierr); 1059fbdc3dfeSToby Isaac ierr = PetscMalloc2(dim, °tup, dim, &ktup);CHKERRQ(ierr); 1060fbdc3dfeSToby Isaac ierr = PetscMalloc1(Ndeg, &scales);CHKERRQ(ierr); 1061fbdc3dfeSToby Isaac initscale = 1.; 1062fbdc3dfeSToby Isaac if (dim > 1) { 1063fbdc3dfeSToby Isaac ierr = PetscDTBinomial(dim,2,&scaleexp);CHKERRQ(ierr); 10642f613bf5SBarry Smith initscale = PetscPowReal(2.,scaleexp*0.5); 1065fbdc3dfeSToby Isaac } 1066fbdc3dfeSToby Isaac for (degidx = 0; degidx < Ndeg; degidx++) { 1067fbdc3dfeSToby Isaac PetscInt e, i; 1068fbdc3dfeSToby Isaac PetscInt m1idx = -1, m2idx = -1; 1069fbdc3dfeSToby Isaac PetscInt n; 1070fbdc3dfeSToby Isaac PetscInt degsum; 1071fbdc3dfeSToby Isaac PetscReal alpha; 1072fbdc3dfeSToby Isaac PetscReal cnm1, cnm1x, cnm2; 1073fbdc3dfeSToby Isaac PetscReal norm; 1074fbdc3dfeSToby Isaac 1075fbdc3dfeSToby Isaac ierr = PetscDTIndexToGradedOrder(dim, degidx, degtup);CHKERRQ(ierr); 1076fbdc3dfeSToby Isaac for (d = dim - 1; d >= 0; d--) if (degtup[d]) break; 1077fbdc3dfeSToby Isaac if (d < 0) { /* constant is 1 everywhere, all derivatives are zero */ 1078fbdc3dfeSToby Isaac scales[degidx] = initscale; 1079fbdc3dfeSToby Isaac for (e = 0; e < dim; e++) { 1080fbdc3dfeSToby Isaac ierr = PetscDTJacobiNorm(e,0.,0,&norm);CHKERRQ(ierr); 1081fbdc3dfeSToby Isaac scales[degidx] /= norm; 1082fbdc3dfeSToby Isaac } 1083fbdc3dfeSToby Isaac for (i = 0; i < npoints; i++) p[degidx * Nk * npoints + i] = 1.; 1084fbdc3dfeSToby Isaac for (i = 0; i < (Nk - 1) * npoints; i++) p[(degidx * Nk + 1) * npoints + i] = 0.; 1085fbdc3dfeSToby Isaac continue; 1086fbdc3dfeSToby Isaac } 1087fbdc3dfeSToby Isaac n = degtup[d]; 1088fbdc3dfeSToby Isaac degtup[d]--; 1089fbdc3dfeSToby Isaac ierr = PetscDTGradedOrderToIndex(dim, degtup, &m1idx);CHKERRQ(ierr); 1090fbdc3dfeSToby Isaac if (degtup[d] > 0) { 1091fbdc3dfeSToby Isaac degtup[d]--; 1092fbdc3dfeSToby Isaac ierr = PetscDTGradedOrderToIndex(dim, degtup, &m2idx);CHKERRQ(ierr); 1093fbdc3dfeSToby Isaac degtup[d]++; 1094fbdc3dfeSToby Isaac } 1095fbdc3dfeSToby Isaac degtup[d]++; 1096fbdc3dfeSToby Isaac for (e = 0, degsum = 0; e < d; e++) degsum += degtup[e]; 1097fbdc3dfeSToby Isaac alpha = 2 * degsum + d; 1098fbdc3dfeSToby Isaac PetscDTJacobiRecurrence_Internal(n,alpha,0.,cnm1,cnm1x,cnm2); 1099fbdc3dfeSToby Isaac 1100fbdc3dfeSToby Isaac scales[degidx] = initscale; 1101fbdc3dfeSToby Isaac for (e = 0, degsum = 0; e < dim; e++) { 1102fbdc3dfeSToby Isaac PetscInt f; 1103fbdc3dfeSToby Isaac PetscReal ealpha; 1104fbdc3dfeSToby Isaac PetscReal enorm; 1105fbdc3dfeSToby Isaac 1106fbdc3dfeSToby Isaac ealpha = 2 * degsum + e; 1107fbdc3dfeSToby Isaac for (f = 0; f < degsum; f++) scales[degidx] *= 2.; 1108fbdc3dfeSToby Isaac ierr = PetscDTJacobiNorm(ealpha,0.,degtup[e],&enorm);CHKERRQ(ierr); 1109fbdc3dfeSToby Isaac scales[degidx] /= enorm; 1110fbdc3dfeSToby Isaac degsum += degtup[e]; 1111fbdc3dfeSToby Isaac } 1112fbdc3dfeSToby Isaac 1113fbdc3dfeSToby Isaac for (pt = 0; pt < npoints; pt++) { 1114fbdc3dfeSToby Isaac /* compute the multipliers */ 1115fbdc3dfeSToby Isaac PetscReal thetanm1, thetanm1x, thetanm2; 1116fbdc3dfeSToby Isaac 1117fbdc3dfeSToby Isaac thetanm1x = dim - (d+1) + 2.*points[pt * dim + d]; 1118fbdc3dfeSToby Isaac for (e = d+1; e < dim; e++) thetanm1x += points[pt * dim + e]; 1119fbdc3dfeSToby Isaac thetanm1x *= 0.5; 1120fbdc3dfeSToby Isaac thetanm1 = (2. - (dim-(d+1))); 1121fbdc3dfeSToby Isaac for (e = d+1; e < dim; e++) thetanm1 -= points[pt * dim + e]; 1122fbdc3dfeSToby Isaac thetanm1 *= 0.5; 1123fbdc3dfeSToby Isaac thetanm2 = thetanm1 * thetanm1; 1124fbdc3dfeSToby Isaac 1125fbdc3dfeSToby Isaac for (kidx = 0; kidx < Nk; kidx++) { 1126fbdc3dfeSToby Isaac PetscInt f; 1127fbdc3dfeSToby Isaac 1128fbdc3dfeSToby Isaac ierr = PetscDTIndexToGradedOrder(dim, kidx, ktup);CHKERRQ(ierr); 1129fbdc3dfeSToby Isaac /* first sum in the same derivative terms */ 1130fbdc3dfeSToby Isaac p[(degidx * Nk + kidx) * npoints + pt] = (cnm1 * thetanm1 + cnm1x * thetanm1x) * p[(m1idx * Nk + kidx) * npoints + pt]; 1131fbdc3dfeSToby Isaac if (m2idx >= 0) { 1132fbdc3dfeSToby Isaac p[(degidx * Nk + kidx) * npoints + pt] -= cnm2 * thetanm2 * p[(m2idx * Nk + kidx) * npoints + pt]; 1133fbdc3dfeSToby Isaac } 1134fbdc3dfeSToby Isaac 1135fbdc3dfeSToby Isaac for (f = d; f < dim; f++) { 1136fbdc3dfeSToby Isaac PetscInt km1idx, mplty = ktup[f]; 1137fbdc3dfeSToby Isaac 1138fbdc3dfeSToby Isaac if (!mplty) continue; 1139fbdc3dfeSToby Isaac ktup[f]--; 1140fbdc3dfeSToby Isaac ierr = PetscDTGradedOrderToIndex(dim, ktup, &km1idx);CHKERRQ(ierr); 1141fbdc3dfeSToby Isaac 1142fbdc3dfeSToby Isaac /* the derivative of cnm1x * thetanm1x wrt x variable f is 0.5 * cnm1x if f > d otherwise it is cnm1x */ 1143fbdc3dfeSToby Isaac /* the derivative of cnm1 * thetanm1 wrt x variable f is 0 if f == d, otherwise it is -0.5 * cnm1 */ 1144fbdc3dfeSToby Isaac /* the derivative of -cnm2 * thetanm2 wrt x variable f is 0 if f == d, otherwise it is cnm2 * thetanm1 */ 1145fbdc3dfeSToby Isaac if (f > d) { 1146fbdc3dfeSToby Isaac PetscInt f2; 1147fbdc3dfeSToby Isaac 1148fbdc3dfeSToby Isaac p[(degidx * Nk + kidx) * npoints + pt] += mplty * 0.5 * (cnm1x - cnm1) * p[(m1idx * Nk + km1idx) * npoints + pt]; 1149fbdc3dfeSToby Isaac if (m2idx >= 0) { 1150fbdc3dfeSToby Isaac p[(degidx * Nk + kidx) * npoints + pt] += mplty * cnm2 * thetanm1 * p[(m2idx * Nk + km1idx) * npoints + pt]; 1151fbdc3dfeSToby Isaac /* second derivatives of -cnm2 * thetanm2 wrt x variable f,f2 is like - 0.5 * cnm2 */ 1152fbdc3dfeSToby Isaac for (f2 = f; f2 < dim; f2++) { 1153fbdc3dfeSToby Isaac PetscInt km2idx, mplty2 = ktup[f2]; 1154fbdc3dfeSToby Isaac PetscInt factor; 1155fbdc3dfeSToby Isaac 1156fbdc3dfeSToby Isaac if (!mplty2) continue; 1157fbdc3dfeSToby Isaac ktup[f2]--; 1158fbdc3dfeSToby Isaac ierr = PetscDTGradedOrderToIndex(dim, ktup, &km2idx);CHKERRQ(ierr); 1159fbdc3dfeSToby Isaac 1160fbdc3dfeSToby Isaac factor = mplty * mplty2; 1161fbdc3dfeSToby Isaac if (f == f2) factor /= 2; 1162fbdc3dfeSToby Isaac p[(degidx * Nk + kidx) * npoints + pt] -= 0.5 * factor * cnm2 * p[(m2idx * Nk + km2idx) * npoints + pt]; 1163fbdc3dfeSToby Isaac ktup[f2]++; 1164fbdc3dfeSToby Isaac } 11653034baaeSToby Isaac } 1166fbdc3dfeSToby Isaac } else { 1167fbdc3dfeSToby Isaac p[(degidx * Nk + kidx) * npoints + pt] += mplty * cnm1x * p[(m1idx * Nk + km1idx) * npoints + pt]; 1168fbdc3dfeSToby Isaac } 1169fbdc3dfeSToby Isaac ktup[f]++; 1170fbdc3dfeSToby Isaac } 1171fbdc3dfeSToby Isaac } 1172fbdc3dfeSToby Isaac } 1173fbdc3dfeSToby Isaac } 1174fbdc3dfeSToby Isaac for (degidx = 0; degidx < Ndeg; degidx++) { 1175fbdc3dfeSToby Isaac PetscReal scale = scales[degidx]; 1176fbdc3dfeSToby Isaac PetscInt i; 1177fbdc3dfeSToby Isaac 1178fbdc3dfeSToby Isaac for (i = 0; i < Nk * npoints; i++) p[degidx*Nk*npoints + i] *= scale; 1179fbdc3dfeSToby Isaac } 1180fbdc3dfeSToby Isaac ierr = PetscFree(scales);CHKERRQ(ierr); 1181fbdc3dfeSToby Isaac ierr = PetscFree2(degtup, ktup);CHKERRQ(ierr); 1182fbdc3dfeSToby Isaac PetscFunctionReturn(0); 1183fbdc3dfeSToby Isaac } 1184fbdc3dfeSToby Isaac 1185d8f25ad8SToby Isaac /*@ 1186d8f25ad8SToby Isaac PetscDTPTrimmedSize - The size of the trimmed polynomial space of k-forms with a given degree and form degree, 1187d8f25ad8SToby Isaac which can be evaluated in PetscDTPTrimmedEvalJet(). 1188d8f25ad8SToby Isaac 1189d8f25ad8SToby Isaac Input Parameters: 1190d8f25ad8SToby Isaac + dim - the number of variables in the multivariate polynomials 1191d8f25ad8SToby Isaac . degree - the degree (sum of degrees on the variables in a monomial) of the trimmed polynomial space. 1192d8f25ad8SToby Isaac - formDegree - the degree of the form 1193d8f25ad8SToby Isaac 1194d8f25ad8SToby Isaac Output Argments: 1195d8f25ad8SToby Isaac - size - The number ((dim + degree) choose (dim + formDegree)) x ((degree + formDegree - 1) choose (formDegree)) 1196d8f25ad8SToby Isaac 1197d8f25ad8SToby Isaac Level: advanced 1198d8f25ad8SToby Isaac 1199d8f25ad8SToby Isaac .seealso: PetscDTPTrimmedEvalJet() 1200d8f25ad8SToby Isaac @*/ 1201d8f25ad8SToby Isaac PetscErrorCode PetscDTPTrimmedSize(PetscInt dim, PetscInt degree, PetscInt formDegree, PetscInt *size) 1202d8f25ad8SToby Isaac { 1203d8f25ad8SToby Isaac PetscInt Nrk, Nbpt; // number of trimmed polynomials 1204d8f25ad8SToby Isaac PetscErrorCode ierr; 1205d8f25ad8SToby Isaac 1206d8f25ad8SToby Isaac PetscFunctionBegin; 1207d8f25ad8SToby Isaac formDegree = PetscAbsInt(formDegree); 1208d8f25ad8SToby Isaac ierr = PetscDTBinomialInt(degree + dim, degree + formDegree, &Nbpt);CHKERRQ(ierr); 1209d8f25ad8SToby Isaac ierr = PetscDTBinomialInt(degree + formDegree - 1, formDegree, &Nrk);CHKERRQ(ierr); 1210d8f25ad8SToby Isaac Nbpt *= Nrk; 1211d8f25ad8SToby Isaac *size = Nbpt; 1212d8f25ad8SToby Isaac PetscFunctionReturn(0); 1213d8f25ad8SToby Isaac } 1214d8f25ad8SToby Isaac 1215d8f25ad8SToby Isaac /* there was a reference implementation based on section 4.4 of Arnold, Falk & Winther (acta numerica, 2006), but it 1216d8f25ad8SToby Isaac * was inferior to this implementation */ 1217d8f25ad8SToby Isaac static PetscErrorCode PetscDTPTrimmedEvalJet_Internal(PetscInt dim, PetscInt npoints, const PetscReal points[], PetscInt degree, PetscInt formDegree, PetscInt jetDegree, PetscReal p[]) 1218d8f25ad8SToby Isaac { 1219d8f25ad8SToby Isaac PetscInt formDegreeOrig = formDegree; 1220d8f25ad8SToby Isaac PetscBool formNegative = (formDegreeOrig < 0) ? PETSC_TRUE : PETSC_FALSE; 1221d8f25ad8SToby Isaac PetscErrorCode ierr; 1222d8f25ad8SToby Isaac 1223d8f25ad8SToby Isaac PetscFunctionBegin; 1224d8f25ad8SToby Isaac formDegree = PetscAbsInt(formDegreeOrig); 1225d8f25ad8SToby Isaac if (formDegree == 0) { 1226d8f25ad8SToby Isaac ierr = PetscDTPKDEvalJet(dim, npoints, points, degree, jetDegree, p);CHKERRQ(ierr); 1227d8f25ad8SToby Isaac PetscFunctionReturn(0); 1228d8f25ad8SToby Isaac } 1229d8f25ad8SToby Isaac if (formDegree == dim) { 1230d8f25ad8SToby Isaac ierr = PetscDTPKDEvalJet(dim, npoints, points, degree - 1, jetDegree, p);CHKERRQ(ierr); 1231d8f25ad8SToby Isaac PetscFunctionReturn(0); 1232d8f25ad8SToby Isaac } 1233d8f25ad8SToby Isaac PetscInt Nbpt; 1234d8f25ad8SToby Isaac ierr = PetscDTPTrimmedSize(dim, degree, formDegree, &Nbpt);CHKERRQ(ierr); 1235d8f25ad8SToby Isaac PetscInt Nf; 1236d8f25ad8SToby Isaac ierr = PetscDTBinomialInt(dim, formDegree, &Nf);CHKERRQ(ierr); 1237d8f25ad8SToby Isaac PetscInt Nk; 1238d8f25ad8SToby Isaac ierr = PetscDTBinomialInt(dim + jetDegree, dim, &Nk);CHKERRQ(ierr); 1239d8f25ad8SToby Isaac ierr = PetscArrayzero(p, Nbpt * Nf * Nk * npoints);CHKERRQ(ierr); 1240d8f25ad8SToby Isaac 1241d8f25ad8SToby Isaac PetscInt Nbpm1; // number of scalar polynomials up to degree - 1; 1242d8f25ad8SToby Isaac ierr = PetscDTBinomialInt(dim + degree - 1, dim, &Nbpm1);CHKERRQ(ierr); 1243d8f25ad8SToby Isaac PetscReal *p_scalar; 1244d8f25ad8SToby Isaac ierr = PetscMalloc1(Nbpm1 * Nk * npoints, &p_scalar);CHKERRQ(ierr); 1245d8f25ad8SToby Isaac ierr = PetscDTPKDEvalJet(dim, npoints, points, degree - 1, jetDegree, p_scalar);CHKERRQ(ierr); 1246d8f25ad8SToby Isaac PetscInt total = 0; 1247d8f25ad8SToby Isaac // First add the full polynomials up to degree - 1 into the basis: take the scalar 1248d8f25ad8SToby Isaac // and copy one for each form component 1249d8f25ad8SToby Isaac for (PetscInt i = 0; i < Nbpm1; i++) { 1250d8f25ad8SToby Isaac const PetscReal *src = &p_scalar[i * Nk * npoints]; 1251d8f25ad8SToby Isaac for (PetscInt f = 0; f < Nf; f++) { 1252d8f25ad8SToby Isaac PetscReal *dest = &p[(total++ * Nf + f) * Nk * npoints]; 1253d8f25ad8SToby Isaac ierr = PetscArraycpy(dest, src, Nk * npoints);CHKERRQ(ierr); 1254d8f25ad8SToby Isaac } 1255d8f25ad8SToby Isaac } 1256d8f25ad8SToby Isaac PetscInt *form_atoms; 1257d8f25ad8SToby Isaac ierr = PetscMalloc1(formDegree + 1, &form_atoms);CHKERRQ(ierr); 1258d8f25ad8SToby Isaac // construct the interior product pattern 1259d8f25ad8SToby Isaac PetscInt (*pattern)[3]; 1260d8f25ad8SToby Isaac PetscInt Nf1; // number of formDegree + 1 forms 1261d8f25ad8SToby Isaac ierr = PetscDTBinomialInt(dim, formDegree + 1, &Nf1);CHKERRQ(ierr); 1262d8f25ad8SToby Isaac PetscInt nnz = Nf1 * (formDegree+1); 1263d8f25ad8SToby Isaac ierr = PetscMalloc1(Nf1 * (formDegree+1), &pattern);CHKERRQ(ierr); 1264d8f25ad8SToby Isaac ierr = PetscDTAltVInteriorPattern(dim, formDegree+1, pattern);CHKERRQ(ierr); 1265d8f25ad8SToby Isaac PetscReal centroid = (1. - dim) / (dim + 1.); 1266d8f25ad8SToby Isaac PetscInt *deriv; 1267d8f25ad8SToby Isaac ierr = PetscMalloc1(dim, &deriv);CHKERRQ(ierr); 1268d8f25ad8SToby Isaac for (PetscInt d = dim; d >= formDegree + 1; d--) { 1269d8f25ad8SToby Isaac PetscInt Nfd1; // number of formDegree + 1 forms in dimension d that include dx_0 1270d8f25ad8SToby Isaac // (equal to the number of formDegree forms in dimension d-1) 1271d8f25ad8SToby Isaac ierr = PetscDTBinomialInt(d - 1, formDegree, &Nfd1);CHKERRQ(ierr); 1272d8f25ad8SToby Isaac // The number of homogeneous (degree-1) scalar polynomials in d variables 1273d8f25ad8SToby Isaac PetscInt Nh; 1274d8f25ad8SToby Isaac ierr = PetscDTBinomialInt(d - 1 + degree - 1, d - 1, &Nh);CHKERRQ(ierr); 1275d8f25ad8SToby Isaac const PetscReal *h_scalar = &p_scalar[(Nbpm1 - Nh) * Nk * npoints]; 1276d8f25ad8SToby Isaac for (PetscInt b = 0; b < Nh; b++) { 1277d8f25ad8SToby Isaac const PetscReal *h_s = &h_scalar[b * Nk * npoints]; 1278d8f25ad8SToby Isaac for (PetscInt f = 0; f < Nfd1; f++) { 1279d8f25ad8SToby Isaac // construct all formDegree+1 forms that start with dx_(dim - d) /\ ... 1280d8f25ad8SToby Isaac form_atoms[0] = dim - d; 1281d8f25ad8SToby Isaac ierr = PetscDTEnumSubset(d-1, formDegree, f, &form_atoms[1]);CHKERRQ(ierr); 1282d8f25ad8SToby Isaac for (PetscInt i = 0; i < formDegree; i++) { 1283d8f25ad8SToby Isaac form_atoms[1+i] += form_atoms[0] + 1; 1284d8f25ad8SToby Isaac } 1285d8f25ad8SToby Isaac PetscInt f_ind; // index of the resulting form 1286d8f25ad8SToby Isaac ierr = PetscDTSubsetIndex(dim, formDegree + 1, form_atoms, &f_ind);CHKERRQ(ierr); 1287d8f25ad8SToby Isaac PetscReal *p_f = &p[total++ * Nf * Nk * npoints]; 1288d8f25ad8SToby Isaac for (PetscInt nz = 0; nz < nnz; nz++) { 1289d8f25ad8SToby Isaac PetscInt i = pattern[nz][0]; // formDegree component 1290d8f25ad8SToby Isaac PetscInt j = pattern[nz][1]; // (formDegree + 1) component 1291d8f25ad8SToby Isaac PetscInt v = pattern[nz][2]; // coordinate component 1292d8f25ad8SToby Isaac PetscReal scale = v < 0 ? -1. : 1.; 1293d8f25ad8SToby Isaac 1294d8f25ad8SToby Isaac i = formNegative ? (Nf - 1 - i) : i; 1295d8f25ad8SToby Isaac scale = (formNegative && (i & 1)) ? -scale : scale; 1296d8f25ad8SToby Isaac v = v < 0 ? -(v + 1) : v; 1297d8f25ad8SToby Isaac if (j != f_ind) { 1298d8f25ad8SToby Isaac continue; 1299d8f25ad8SToby Isaac } 1300d8f25ad8SToby Isaac PetscReal *p_i = &p_f[i * Nk * npoints]; 1301d8f25ad8SToby Isaac for (PetscInt jet = 0; jet < Nk; jet++) { 1302d8f25ad8SToby Isaac const PetscReal *h_jet = &h_s[jet * npoints]; 1303d8f25ad8SToby Isaac PetscReal *p_jet = &p_i[jet * npoints]; 1304d8f25ad8SToby Isaac 1305d8f25ad8SToby Isaac for (PetscInt pt = 0; pt < npoints; pt++) { 1306d8f25ad8SToby Isaac p_jet[pt] += scale * h_jet[pt] * (points[pt * dim + v] - centroid); 1307d8f25ad8SToby Isaac } 1308d8f25ad8SToby Isaac ierr = PetscDTIndexToGradedOrder(dim, jet, deriv);CHKERRQ(ierr); 1309d8f25ad8SToby Isaac deriv[v]++; 1310d8f25ad8SToby Isaac PetscReal mult = deriv[v]; 1311d8f25ad8SToby Isaac PetscInt l; 1312d8f25ad8SToby Isaac ierr = PetscDTGradedOrderToIndex(dim, deriv, &l);CHKERRQ(ierr); 1313d8f25ad8SToby Isaac if (l >= Nk) { 1314d8f25ad8SToby Isaac continue; 1315d8f25ad8SToby Isaac } 1316d8f25ad8SToby Isaac p_jet = &p_i[l * npoints]; 1317d8f25ad8SToby Isaac for (PetscInt pt = 0; pt < npoints; pt++) { 1318d8f25ad8SToby Isaac p_jet[pt] += scale * mult * h_jet[pt]; 1319d8f25ad8SToby Isaac } 1320d8f25ad8SToby Isaac deriv[v]--; 1321d8f25ad8SToby Isaac } 1322d8f25ad8SToby Isaac } 1323d8f25ad8SToby Isaac } 1324d8f25ad8SToby Isaac } 1325d8f25ad8SToby Isaac } 13262c71b3e2SJacob Faibussowitsch PetscCheckFalse(total != Nbpt,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Incorrectly counted P trimmed polynomials"); 1327d8f25ad8SToby Isaac ierr = PetscFree(deriv);CHKERRQ(ierr); 1328d8f25ad8SToby Isaac ierr = PetscFree(pattern);CHKERRQ(ierr); 1329d8f25ad8SToby Isaac ierr = PetscFree(form_atoms);CHKERRQ(ierr); 1330d8f25ad8SToby Isaac ierr = PetscFree(p_scalar);CHKERRQ(ierr); 1331d8f25ad8SToby Isaac PetscFunctionReturn(0); 1332d8f25ad8SToby Isaac } 1333d8f25ad8SToby Isaac 1334d8f25ad8SToby Isaac /*@ 1335d8f25ad8SToby Isaac PetscDTPTrimmedEvalJet - Evaluate the jet (function and derivatives) of a basis of the trimmed polynomial k-forms up to 1336d8f25ad8SToby Isaac a given degree. 1337d8f25ad8SToby Isaac 1338d8f25ad8SToby Isaac Input Parameters: 1339d8f25ad8SToby Isaac + dim - the number of variables in the multivariate polynomials 1340d8f25ad8SToby Isaac . npoints - the number of points to evaluate the polynomials at 1341d8f25ad8SToby Isaac . points - [npoints x dim] array of point coordinates 1342d8f25ad8SToby Isaac . degree - the degree (sum of degrees on the variables in a monomial) of the trimmed polynomial space to evaluate. 1343d8f25ad8SToby Isaac There are ((dim + degree) choose (dim + formDegree)) x ((degree + formDegree - 1) choose (formDegree)) polynomials in this space. 1344d8f25ad8SToby Isaac (You can use PetscDTPTrimmedSize() to compute this size.) 1345d8f25ad8SToby Isaac . formDegree - the degree of the form 1346d8f25ad8SToby Isaac - jetDegree - the maximum order partial derivative to evaluate in the jet. There are ((dim + jetDegree) choose dim) partial derivatives 1347d8f25ad8SToby Isaac in the jet. Choosing jetDegree = 0 means to evaluate just the function and no derivatives 1348d8f25ad8SToby Isaac 1349d8f25ad8SToby Isaac Output Argments: 1350d8f25ad8SToby Isaac - p - an array containing the evaluations of the PKD polynomials' jets on the points. The size is 1351d8f25ad8SToby Isaac PetscDTPTrimmedSize() x ((dim + formDegree) choose dim) x ((dim + k) choose dim) x npoints, 1352d8f25ad8SToby Isaac which also describes the order of the dimensions of this 1353d8f25ad8SToby Isaac four-dimensional array: 1354d8f25ad8SToby Isaac the first (slowest varying) dimension is basis function index; 1355d8f25ad8SToby Isaac the second dimension is component of the form; 1356d8f25ad8SToby Isaac the third dimension is jet index; 1357d8f25ad8SToby Isaac the fourth (fastest varying) dimension is the index of the evaluation point. 1358d8f25ad8SToby Isaac 1359d8f25ad8SToby Isaac Level: advanced 1360d8f25ad8SToby Isaac 1361d8f25ad8SToby Isaac Note: The ordering of the basis functions is not graded, so the basis functions are not nested by degree like PetscDTPKDEvalJet(). 1362d8f25ad8SToby Isaac The basis functions are not an L2-orthonormal basis on any particular domain. 1363d8f25ad8SToby Isaac 1364d8f25ad8SToby Isaac The implementation is based on the description of the trimmed polynomials up to degree r as 1365d8f25ad8SToby Isaac the direct sum of polynomials up to degree (r-1) and the Koszul differential applied to 1366d8f25ad8SToby Isaac homogeneous polynomials of degree (r-1). 1367d8f25ad8SToby Isaac 1368d8f25ad8SToby Isaac .seealso: PetscDTPKDEvalJet(), PetscDTPTrimmedSize() 1369d8f25ad8SToby Isaac @*/ 1370d8f25ad8SToby Isaac PetscErrorCode PetscDTPTrimmedEvalJet(PetscInt dim, PetscInt npoints, const PetscReal points[], PetscInt degree, PetscInt formDegree, PetscInt jetDegree, PetscReal p[]) 1371d8f25ad8SToby Isaac { 1372d8f25ad8SToby Isaac PetscErrorCode ierr; 1373d8f25ad8SToby Isaac 1374d8f25ad8SToby Isaac PetscFunctionBegin; 1375d8f25ad8SToby Isaac ierr = PetscDTPTrimmedEvalJet_Internal(dim, npoints, points, degree, formDegree, jetDegree, p);CHKERRQ(ierr); 1376d8f25ad8SToby Isaac PetscFunctionReturn(0); 1377d8f25ad8SToby Isaac } 1378d8f25ad8SToby Isaac 1379e6a796c3SToby Isaac /* solve the symmetric tridiagonal eigenvalue system, writing the eigenvalues into eigs and the eigenvectors into V 1380e6a796c3SToby Isaac * with lds n; diag and subdiag are overwritten */ 1381e6a796c3SToby Isaac static PetscErrorCode PetscDTSymmetricTridiagonalEigensolve(PetscInt n, PetscReal diag[], PetscReal subdiag[], 1382e6a796c3SToby Isaac PetscReal eigs[], PetscScalar V[]) 1383e6a796c3SToby Isaac { 1384e6a796c3SToby Isaac char jobz = 'V'; /* eigenvalues and eigenvectors */ 1385e6a796c3SToby Isaac char range = 'A'; /* all eigenvalues will be found */ 1386e6a796c3SToby Isaac PetscReal VL = 0.; /* ignored because range is 'A' */ 1387e6a796c3SToby Isaac PetscReal VU = 0.; /* ignored because range is 'A' */ 1388e6a796c3SToby Isaac PetscBLASInt IL = 0; /* ignored because range is 'A' */ 1389e6a796c3SToby Isaac PetscBLASInt IU = 0; /* ignored because range is 'A' */ 1390e6a796c3SToby Isaac PetscReal abstol = 0.; /* unused */ 1391e6a796c3SToby Isaac PetscBLASInt bn, bm, ldz; /* bm will equal bn on exit */ 1392e6a796c3SToby Isaac PetscBLASInt *isuppz; 1393e6a796c3SToby Isaac PetscBLASInt lwork, liwork; 1394e6a796c3SToby Isaac PetscReal workquery; 1395e6a796c3SToby Isaac PetscBLASInt iworkquery; 1396e6a796c3SToby Isaac PetscBLASInt *iwork; 1397e6a796c3SToby Isaac PetscBLASInt info; 1398e6a796c3SToby Isaac PetscReal *work = NULL; 1399e6a796c3SToby Isaac PetscErrorCode ierr; 1400e6a796c3SToby Isaac 1401e6a796c3SToby Isaac PetscFunctionBegin; 1402e6a796c3SToby Isaac #if !defined(PETSCDTGAUSSIANQUADRATURE_EIG) 1403e6a796c3SToby Isaac SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "A LAPACK symmetric tridiagonal eigensolver could not be found"); 1404e6a796c3SToby Isaac #endif 1405e6a796c3SToby Isaac ierr = PetscBLASIntCast(n, &bn);CHKERRQ(ierr); 1406e6a796c3SToby Isaac ierr = PetscBLASIntCast(n, &ldz);CHKERRQ(ierr); 1407e6a796c3SToby Isaac #if !defined(PETSC_MISSING_LAPACK_STEGR) 1408e6a796c3SToby Isaac ierr = PetscMalloc1(2 * n, &isuppz);CHKERRQ(ierr); 1409e6a796c3SToby Isaac lwork = -1; 1410e6a796c3SToby Isaac liwork = -1; 1411e6a796c3SToby Isaac PetscStackCallBLAS("LAPACKstegr",LAPACKstegr_(&jobz,&range,&bn,diag,subdiag,&VL,&VU,&IL,&IU,&abstol,&bm,eigs,V,&ldz,isuppz,&workquery,&lwork,&iworkquery,&liwork,&info)); 14122c71b3e2SJacob Faibussowitsch PetscCheckFalse(info,PETSC_COMM_SELF,PETSC_ERR_PLIB,"xSTEGR error"); 1413e6a796c3SToby Isaac lwork = (PetscBLASInt) workquery; 1414e6a796c3SToby Isaac liwork = (PetscBLASInt) iworkquery; 1415e6a796c3SToby Isaac ierr = PetscMalloc2(lwork, &work, liwork, &iwork);CHKERRQ(ierr); 1416e6a796c3SToby Isaac ierr = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr); 1417e6a796c3SToby Isaac PetscStackCallBLAS("LAPACKstegr",LAPACKstegr_(&jobz,&range,&bn,diag,subdiag,&VL,&VU,&IL,&IU,&abstol,&bm,eigs,V,&ldz,isuppz,work,&lwork,iwork,&liwork,&info)); 1418e6a796c3SToby Isaac ierr = PetscFPTrapPop();CHKERRQ(ierr); 14192c71b3e2SJacob Faibussowitsch PetscCheckFalse(info,PETSC_COMM_SELF,PETSC_ERR_PLIB,"xSTEGR error"); 1420e6a796c3SToby Isaac ierr = PetscFree2(work, iwork);CHKERRQ(ierr); 1421e6a796c3SToby Isaac ierr = PetscFree(isuppz);CHKERRQ(ierr); 1422e6a796c3SToby Isaac #elif !defined(PETSC_MISSING_LAPACK_STEQR) 1423e6a796c3SToby Isaac jobz = 'I'; /* Compute eigenvalues and eigenvectors of the 1424e6a796c3SToby Isaac tridiagonal matrix. Z is initialized to the identity 1425e6a796c3SToby Isaac matrix. */ 1426e6a796c3SToby Isaac ierr = PetscMalloc1(PetscMax(1,2*n-2),&work);CHKERRQ(ierr); 1427e6a796c3SToby Isaac PetscStackCallBLAS("LAPACKsteqr",LAPACKsteqr_("I",&bn,diag,subdiag,V,&ldz,work,&info)); 1428e6a796c3SToby Isaac ierr = PetscFPTrapPop();CHKERRQ(ierr); 14292c71b3e2SJacob Faibussowitsch PetscCheckFalse(info,PETSC_COMM_SELF,PETSC_ERR_PLIB,"xSTEQR error"); 1430e6a796c3SToby Isaac ierr = PetscFree(work);CHKERRQ(ierr); 1431e6a796c3SToby Isaac ierr = PetscArraycpy(eigs,diag,n);CHKERRQ(ierr); 1432e6a796c3SToby Isaac #endif 1433e6a796c3SToby Isaac PetscFunctionReturn(0); 1434e6a796c3SToby Isaac } 1435e6a796c3SToby Isaac 1436e6a796c3SToby Isaac /* Formula for the weights at the endpoints (-1 and 1) of Gauss-Lobatto-Jacobi 1437e6a796c3SToby Isaac * quadrature rules on the interval [-1, 1] */ 1438e6a796c3SToby Isaac static PetscErrorCode PetscDTGaussLobattoJacobiEndweights_Internal(PetscInt n, PetscReal alpha, PetscReal beta, PetscReal *leftw, PetscReal *rightw) 1439e6a796c3SToby Isaac { 1440e6a796c3SToby Isaac PetscReal twoab1; 1441e6a796c3SToby Isaac PetscInt m = n - 2; 1442e6a796c3SToby Isaac PetscReal a = alpha + 1.; 1443e6a796c3SToby Isaac PetscReal b = beta + 1.; 1444e6a796c3SToby Isaac PetscReal gra, grb; 1445e6a796c3SToby Isaac 1446e6a796c3SToby Isaac PetscFunctionBegin; 1447e6a796c3SToby Isaac twoab1 = PetscPowReal(2., a + b - 1.); 1448e6a796c3SToby Isaac #if defined(PETSC_HAVE_LGAMMA) 1449e6a796c3SToby Isaac grb = PetscExpReal(2. * PetscLGamma(b+1.) + PetscLGamma(m+1.) + PetscLGamma(m+a+1.) - 1450e6a796c3SToby Isaac (PetscLGamma(m+b+1) + PetscLGamma(m+a+b+1.))); 1451e6a796c3SToby Isaac gra = PetscExpReal(2. * PetscLGamma(a+1.) + PetscLGamma(m+1.) + PetscLGamma(m+b+1.) - 1452e6a796c3SToby Isaac (PetscLGamma(m+a+1) + PetscLGamma(m+a+b+1.))); 1453e6a796c3SToby Isaac #else 1454e6a796c3SToby Isaac { 1455e6a796c3SToby Isaac PetscInt alphai = (PetscInt) alpha; 1456e6a796c3SToby Isaac PetscInt betai = (PetscInt) beta; 145794e21283SToby Isaac PetscErrorCode ierr; 1458e6a796c3SToby Isaac 1459e6a796c3SToby Isaac if ((PetscReal) alphai == alpha && (PetscReal) betai == beta) { 1460e6a796c3SToby Isaac PetscReal binom1, binom2; 1461e6a796c3SToby Isaac 1462e6a796c3SToby Isaac ierr = PetscDTBinomial(m+b, b, &binom1);CHKERRQ(ierr); 1463e6a796c3SToby Isaac ierr = PetscDTBinomial(m+a+b, b, &binom2);CHKERRQ(ierr); 1464e6a796c3SToby Isaac grb = 1./ (binom1 * binom2); 1465e6a796c3SToby Isaac ierr = PetscDTBinomial(m+a, a, &binom1);CHKERRQ(ierr); 1466e6a796c3SToby Isaac ierr = PetscDTBinomial(m+a+b, a, &binom2);CHKERRQ(ierr); 1467e6a796c3SToby Isaac gra = 1./ (binom1 * binom2); 1468e6a796c3SToby Isaac } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"lgamma() - math routine is unavailable."); 1469e6a796c3SToby Isaac } 1470e6a796c3SToby Isaac #endif 1471e6a796c3SToby Isaac *leftw = twoab1 * grb / b; 1472e6a796c3SToby Isaac *rightw = twoab1 * gra / a; 1473e6a796c3SToby Isaac PetscFunctionReturn(0); 1474e6a796c3SToby Isaac } 1475e6a796c3SToby Isaac 1476e6a796c3SToby Isaac /* Evaluates the nth jacobi polynomial with weight parameters a,b at a point x. 1477e6a796c3SToby Isaac Recurrence relations implemented from the pseudocode given in Karniadakis and Sherwin, Appendix B */ 14789fbee547SJacob Faibussowitsch static inline PetscErrorCode PetscDTComputeJacobi(PetscReal a, PetscReal b, PetscInt n, PetscReal x, PetscReal *P) 1479e6a796c3SToby Isaac { 148094e21283SToby Isaac PetscReal pn1, pn2; 148194e21283SToby Isaac PetscReal cnm1, cnm1x, cnm2; 1482e6a796c3SToby Isaac PetscInt k; 1483e6a796c3SToby Isaac 1484e6a796c3SToby Isaac PetscFunctionBegin; 1485e6a796c3SToby Isaac if (!n) {*P = 1.0; PetscFunctionReturn(0);} 148694e21283SToby Isaac PetscDTJacobiRecurrence_Internal(1,a,b,cnm1,cnm1x,cnm2); 148794e21283SToby Isaac pn2 = 1.; 148894e21283SToby Isaac pn1 = cnm1 + cnm1x*x; 148994e21283SToby Isaac if (n == 1) {*P = pn1; PetscFunctionReturn(0);} 1490e6a796c3SToby Isaac *P = 0.0; 1491e6a796c3SToby Isaac for (k = 2; k < n+1; ++k) { 149294e21283SToby Isaac PetscDTJacobiRecurrence_Internal(k,a,b,cnm1,cnm1x,cnm2); 1493e6a796c3SToby Isaac 149494e21283SToby Isaac *P = (cnm1 + cnm1x*x)*pn1 - cnm2*pn2; 1495e6a796c3SToby Isaac pn2 = pn1; 1496e6a796c3SToby Isaac pn1 = *P; 1497e6a796c3SToby Isaac } 1498e6a796c3SToby Isaac PetscFunctionReturn(0); 1499e6a796c3SToby Isaac } 1500e6a796c3SToby Isaac 1501e6a796c3SToby Isaac /* Evaluates the first derivative of P_{n}^{a,b} at a point x. */ 15029fbee547SJacob Faibussowitsch static inline PetscErrorCode PetscDTComputeJacobiDerivative(PetscReal a, PetscReal b, PetscInt n, PetscReal x, PetscInt k, PetscReal *P) 1503e6a796c3SToby Isaac { 1504e6a796c3SToby Isaac PetscReal nP; 1505e6a796c3SToby Isaac PetscInt i; 1506e6a796c3SToby Isaac PetscErrorCode ierr; 1507e6a796c3SToby Isaac 1508e6a796c3SToby Isaac PetscFunctionBegin; 150917a42bb7SSatish Balay *P = 0.0; 151017a42bb7SSatish Balay if (k > n) PetscFunctionReturn(0); 1511e6a796c3SToby Isaac ierr = PetscDTComputeJacobi(a+k, b+k, n-k, x, &nP);CHKERRQ(ierr); 1512e6a796c3SToby Isaac for (i = 0; i < k; i++) nP *= (a + b + n + 1. + i) * 0.5; 1513e6a796c3SToby Isaac *P = nP; 1514e6a796c3SToby Isaac PetscFunctionReturn(0); 1515e6a796c3SToby Isaac } 1516e6a796c3SToby Isaac 1517e6a796c3SToby Isaac static PetscErrorCode PetscDTGaussJacobiQuadrature_Newton_Internal(PetscInt npoints, PetscReal a, PetscReal b, PetscReal x[], PetscReal w[]) 1518e6a796c3SToby Isaac { 1519e6a796c3SToby Isaac PetscInt maxIter = 100; 152094e21283SToby Isaac PetscReal eps = PetscExpReal(0.75 * PetscLogReal(PETSC_MACHINE_EPSILON)); 1521200b5abcSJed Brown PetscReal a1, a6, gf; 1522e6a796c3SToby Isaac PetscInt k; 1523e6a796c3SToby Isaac PetscErrorCode ierr; 1524e6a796c3SToby Isaac 1525e6a796c3SToby Isaac PetscFunctionBegin; 1526e6a796c3SToby Isaac 1527e6a796c3SToby Isaac a1 = PetscPowReal(2.0, a+b+1); 152894e21283SToby Isaac #if defined(PETSC_HAVE_LGAMMA) 1529200b5abcSJed Brown { 1530200b5abcSJed Brown PetscReal a2, a3, a4, a5; 153194e21283SToby Isaac a2 = PetscLGamma(a + npoints + 1); 153294e21283SToby Isaac a3 = PetscLGamma(b + npoints + 1); 153394e21283SToby Isaac a4 = PetscLGamma(a + b + npoints + 1); 153494e21283SToby Isaac a5 = PetscLGamma(npoints + 1); 153594e21283SToby Isaac gf = PetscExpReal(a2 + a3 - (a4 + a5)); 1536200b5abcSJed Brown } 1537e6a796c3SToby Isaac #else 1538e6a796c3SToby Isaac { 1539e6a796c3SToby Isaac PetscInt ia, ib; 1540e6a796c3SToby Isaac 1541e6a796c3SToby Isaac ia = (PetscInt) a; 1542e6a796c3SToby Isaac ib = (PetscInt) b; 154394e21283SToby Isaac gf = 1.; 154494e21283SToby Isaac if (ia == a && ia >= 0) { /* compute ratio of rising factorals wrt a */ 154594e21283SToby Isaac for (k = 0; k < ia; k++) gf *= (npoints + 1. + k) / (npoints + b + 1. + k); 154694e21283SToby Isaac } else if (b == b && ib >= 0) { /* compute ratio of rising factorials wrt b */ 154794e21283SToby Isaac for (k = 0; k < ib; k++) gf *= (npoints + 1. + k) / (npoints + a + 1. + k); 154894e21283SToby Isaac } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"lgamma() - math routine is unavailable."); 1549e6a796c3SToby Isaac } 1550e6a796c3SToby Isaac #endif 1551e6a796c3SToby Isaac 155294e21283SToby Isaac a6 = a1 * gf; 1553e6a796c3SToby Isaac /* Computes the m roots of P_{m}^{a,b} on [-1,1] by Newton's method with Chebyshev points as initial guesses. 1554e6a796c3SToby Isaac Algorithm implemented from the pseudocode given by Karniadakis and Sherwin and Python in FIAT */ 1555e6a796c3SToby Isaac for (k = 0; k < npoints; ++k) { 155694e21283SToby Isaac PetscReal r = PetscCosReal(PETSC_PI * (1. - (4.*k + 3. + 2.*b) / (4.*npoints + 2.*(a + b + 1.)))), dP; 1557e6a796c3SToby Isaac PetscInt j; 1558e6a796c3SToby Isaac 1559e6a796c3SToby Isaac if (k > 0) r = 0.5 * (r + x[k-1]); 1560e6a796c3SToby Isaac for (j = 0; j < maxIter; ++j) { 1561e6a796c3SToby Isaac PetscReal s = 0.0, delta, f, fp; 1562e6a796c3SToby Isaac PetscInt i; 1563e6a796c3SToby Isaac 1564e6a796c3SToby Isaac for (i = 0; i < k; ++i) s = s + 1.0 / (r - x[i]); 1565e6a796c3SToby Isaac ierr = PetscDTComputeJacobi(a, b, npoints, r, &f);CHKERRQ(ierr); 1566e6a796c3SToby Isaac ierr = PetscDTComputeJacobiDerivative(a, b, npoints, r, 1, &fp);CHKERRQ(ierr); 1567e6a796c3SToby Isaac delta = f / (fp - f * s); 1568e6a796c3SToby Isaac r = r - delta; 1569e6a796c3SToby Isaac if (PetscAbsReal(delta) < eps) break; 1570e6a796c3SToby Isaac } 1571e6a796c3SToby Isaac x[k] = r; 1572e6a796c3SToby Isaac ierr = PetscDTComputeJacobiDerivative(a, b, npoints, x[k], 1, &dP);CHKERRQ(ierr); 1573e6a796c3SToby Isaac w[k] = a6 / (1.0 - PetscSqr(x[k])) / PetscSqr(dP); 1574e6a796c3SToby Isaac } 1575e6a796c3SToby Isaac PetscFunctionReturn(0); 1576e6a796c3SToby Isaac } 1577e6a796c3SToby Isaac 157894e21283SToby Isaac /* Compute the diagonals of the Jacobi matrix used in Golub & Welsch algorithms for Gauss-Jacobi 1579e6a796c3SToby Isaac * quadrature weight calculations on [-1,1] for exponents (1. + x)^a (1.-x)^b */ 1580e6a796c3SToby Isaac static PetscErrorCode PetscDTJacobiMatrix_Internal(PetscInt nPoints, PetscReal a, PetscReal b, PetscReal *d, PetscReal *s) 1581e6a796c3SToby Isaac { 1582e6a796c3SToby Isaac PetscInt i; 1583e6a796c3SToby Isaac 1584e6a796c3SToby Isaac PetscFunctionBegin; 1585e6a796c3SToby Isaac for (i = 0; i < nPoints; i++) { 158694e21283SToby Isaac PetscReal A, B, C; 1587e6a796c3SToby Isaac 158894e21283SToby Isaac PetscDTJacobiRecurrence_Internal(i+1,a,b,A,B,C); 158994e21283SToby Isaac d[i] = -A / B; 159094e21283SToby Isaac if (i) s[i-1] *= C / B; 159194e21283SToby Isaac if (i < nPoints - 1) s[i] = 1. / B; 1592e6a796c3SToby Isaac } 1593e6a796c3SToby Isaac PetscFunctionReturn(0); 1594e6a796c3SToby Isaac } 1595e6a796c3SToby Isaac 1596e6a796c3SToby Isaac static PetscErrorCode PetscDTGaussJacobiQuadrature_GolubWelsch_Internal(PetscInt npoints, PetscReal a, PetscReal b, PetscReal *x, PetscReal *w) 1597e6a796c3SToby Isaac { 1598e6a796c3SToby Isaac PetscReal mu0; 1599e6a796c3SToby Isaac PetscReal ga, gb, gab; 1600e6a796c3SToby Isaac PetscInt i; 1601e6a796c3SToby Isaac PetscErrorCode ierr; 1602e6a796c3SToby Isaac 1603e6a796c3SToby Isaac PetscFunctionBegin; 1604e6a796c3SToby Isaac ierr = PetscCitationsRegister(GolubWelschCitation, &GolubWelschCite);CHKERRQ(ierr); 1605e6a796c3SToby Isaac 1606e6a796c3SToby Isaac #if defined(PETSC_HAVE_TGAMMA) 1607e6a796c3SToby Isaac ga = PetscTGamma(a + 1); 1608e6a796c3SToby Isaac gb = PetscTGamma(b + 1); 1609e6a796c3SToby Isaac gab = PetscTGamma(a + b + 2); 1610e6a796c3SToby Isaac #else 1611e6a796c3SToby Isaac { 1612e6a796c3SToby Isaac PetscInt ia, ib; 1613e6a796c3SToby Isaac 1614e6a796c3SToby Isaac ia = (PetscInt) a; 1615e6a796c3SToby Isaac ib = (PetscInt) b; 1616e6a796c3SToby Isaac if (ia == a && ib == b && ia + 1 > 0 && ib + 1 > 0 && ia + ib + 2 > 0) { /* All gamma(x) terms are (x-1)! terms */ 1617e6a796c3SToby Isaac ierr = PetscDTFactorial(ia, &ga);CHKERRQ(ierr); 1618e6a796c3SToby Isaac ierr = PetscDTFactorial(ib, &gb);CHKERRQ(ierr); 1619e6a796c3SToby Isaac ierr = PetscDTFactorial(ia + ib + 1, &gb);CHKERRQ(ierr); 1620e6a796c3SToby Isaac } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"tgamma() - math routine is unavailable."); 1621e6a796c3SToby Isaac } 1622e6a796c3SToby Isaac #endif 1623e6a796c3SToby Isaac mu0 = PetscPowReal(2.,a + b + 1.) * ga * gb / gab; 1624e6a796c3SToby Isaac 1625e6a796c3SToby Isaac #if defined(PETSCDTGAUSSIANQUADRATURE_EIG) 1626e6a796c3SToby Isaac { 1627e6a796c3SToby Isaac PetscReal *diag, *subdiag; 1628e6a796c3SToby Isaac PetscScalar *V; 1629e6a796c3SToby Isaac 1630e6a796c3SToby Isaac ierr = PetscMalloc2(npoints, &diag, npoints, &subdiag);CHKERRQ(ierr); 1631e6a796c3SToby Isaac ierr = PetscMalloc1(npoints*npoints, &V);CHKERRQ(ierr); 1632e6a796c3SToby Isaac ierr = PetscDTJacobiMatrix_Internal(npoints, a, b, diag, subdiag);CHKERRQ(ierr); 1633e6a796c3SToby Isaac for (i = 0; i < npoints - 1; i++) subdiag[i] = PetscSqrtReal(subdiag[i]); 1634e6a796c3SToby Isaac ierr = PetscDTSymmetricTridiagonalEigensolve(npoints, diag, subdiag, x, V);CHKERRQ(ierr); 163594e21283SToby Isaac for (i = 0; i < npoints; i++) w[i] = PetscSqr(PetscRealPart(V[i * npoints])) * mu0; 1636e6a796c3SToby Isaac ierr = PetscFree(V);CHKERRQ(ierr); 1637e6a796c3SToby Isaac ierr = PetscFree2(diag, subdiag);CHKERRQ(ierr); 1638e6a796c3SToby Isaac } 1639e6a796c3SToby Isaac #else 1640e6a796c3SToby Isaac SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "A LAPACK symmetric tridiagonal eigensolver could not be found"); 1641e6a796c3SToby Isaac #endif 164294e21283SToby Isaac { /* As of March 2, 2020, The Sun Performance Library breaks the LAPACK contract for xstegr and xsteqr: the 164394e21283SToby Isaac eigenvalues are not guaranteed to be in ascending order. So we heave a passive aggressive sigh and check that 164494e21283SToby Isaac the eigenvalues are sorted */ 164594e21283SToby Isaac PetscBool sorted; 164694e21283SToby Isaac 164794e21283SToby Isaac ierr = PetscSortedReal(npoints, x, &sorted);CHKERRQ(ierr); 164894e21283SToby Isaac if (!sorted) { 164994e21283SToby Isaac PetscInt *order, i; 165094e21283SToby Isaac PetscReal *tmp; 165194e21283SToby Isaac 165294e21283SToby Isaac ierr = PetscMalloc2(npoints, &order, npoints, &tmp);CHKERRQ(ierr); 165394e21283SToby Isaac for (i = 0; i < npoints; i++) order[i] = i; 165494e21283SToby Isaac ierr = PetscSortRealWithPermutation(npoints, x, order);CHKERRQ(ierr); 165594e21283SToby Isaac ierr = PetscArraycpy(tmp, x, npoints);CHKERRQ(ierr); 165694e21283SToby Isaac for (i = 0; i < npoints; i++) x[i] = tmp[order[i]]; 165794e21283SToby Isaac ierr = PetscArraycpy(tmp, w, npoints);CHKERRQ(ierr); 165894e21283SToby Isaac for (i = 0; i < npoints; i++) w[i] = tmp[order[i]]; 165994e21283SToby Isaac ierr = PetscFree2(order, tmp);CHKERRQ(ierr); 166094e21283SToby Isaac } 166194e21283SToby Isaac } 1662e6a796c3SToby Isaac PetscFunctionReturn(0); 1663e6a796c3SToby Isaac } 1664e6a796c3SToby Isaac 1665e6a796c3SToby Isaac static PetscErrorCode PetscDTGaussJacobiQuadrature_Internal(PetscInt npoints,PetscReal alpha, PetscReal beta, PetscReal x[], PetscReal w[], PetscBool newton) 1666e6a796c3SToby Isaac { 1667e6a796c3SToby Isaac PetscErrorCode ierr; 1668e6a796c3SToby Isaac 1669e6a796c3SToby Isaac PetscFunctionBegin; 16702c71b3e2SJacob Faibussowitsch PetscCheckFalse(npoints < 1,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Number of points must be positive"); 1671e6a796c3SToby Isaac /* If asking for a 1D Lobatto point, just return the non-Lobatto 1D point */ 16722c71b3e2SJacob Faibussowitsch PetscCheckFalse(alpha <= -1.,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"alpha must be > -1."); 16732c71b3e2SJacob Faibussowitsch PetscCheckFalse(beta <= -1.,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"beta must be > -1."); 1674e6a796c3SToby Isaac 1675e6a796c3SToby Isaac if (newton) { 1676e6a796c3SToby Isaac ierr = PetscDTGaussJacobiQuadrature_Newton_Internal(npoints, alpha, beta, x, w);CHKERRQ(ierr); 1677e6a796c3SToby Isaac } else { 1678e6a796c3SToby Isaac ierr = PetscDTGaussJacobiQuadrature_GolubWelsch_Internal(npoints, alpha, beta, x, w);CHKERRQ(ierr); 1679e6a796c3SToby Isaac } 1680e6a796c3SToby Isaac if (alpha == beta) { /* symmetrize */ 1681e6a796c3SToby Isaac PetscInt i; 1682e6a796c3SToby Isaac for (i = 0; i < (npoints + 1) / 2; i++) { 1683e6a796c3SToby Isaac PetscInt j = npoints - 1 - i; 1684e6a796c3SToby Isaac PetscReal xi = x[i]; 1685e6a796c3SToby Isaac PetscReal xj = x[j]; 1686e6a796c3SToby Isaac PetscReal wi = w[i]; 1687e6a796c3SToby Isaac PetscReal wj = w[j]; 1688e6a796c3SToby Isaac 1689e6a796c3SToby Isaac x[i] = (xi - xj) / 2.; 1690e6a796c3SToby Isaac x[j] = (xj - xi) / 2.; 1691e6a796c3SToby Isaac w[i] = w[j] = (wi + wj) / 2.; 1692e6a796c3SToby Isaac } 1693e6a796c3SToby Isaac } 1694e6a796c3SToby Isaac PetscFunctionReturn(0); 1695e6a796c3SToby Isaac } 1696e6a796c3SToby Isaac 169794e21283SToby Isaac /*@ 169894e21283SToby Isaac PetscDTGaussJacobiQuadrature - quadrature for the interval [a, b] with the weight function 169994e21283SToby Isaac $(x-a)^\alpha (x-b)^\beta$. 170094e21283SToby Isaac 170194e21283SToby Isaac Not collective 170294e21283SToby Isaac 170394e21283SToby Isaac Input Parameters: 170494e21283SToby Isaac + npoints - the number of points in the quadrature rule 170594e21283SToby Isaac . a - the left endpoint of the interval 170694e21283SToby Isaac . b - the right endpoint of the interval 170794e21283SToby Isaac . alpha - the left exponent 170894e21283SToby Isaac - beta - the right exponent 170994e21283SToby Isaac 171094e21283SToby Isaac Output Parameters: 171194e21283SToby Isaac + x - array of length npoints, the locations of the quadrature points 171294e21283SToby Isaac - w - array of length npoints, the weights of the quadrature points 171394e21283SToby Isaac 171494e21283SToby Isaac Level: intermediate 171594e21283SToby Isaac 171694e21283SToby Isaac Note: this quadrature rule is exact for polynomials up to degree 2*npoints - 1. 171794e21283SToby Isaac @*/ 171894e21283SToby Isaac PetscErrorCode PetscDTGaussJacobiQuadrature(PetscInt npoints,PetscReal a, PetscReal b, PetscReal alpha, PetscReal beta, PetscReal x[], PetscReal w[]) 1719e6a796c3SToby Isaac { 172094e21283SToby Isaac PetscInt i; 1721e6a796c3SToby Isaac PetscErrorCode ierr; 1722e6a796c3SToby Isaac 1723e6a796c3SToby Isaac PetscFunctionBegin; 172494e21283SToby Isaac ierr = PetscDTGaussJacobiQuadrature_Internal(npoints, alpha, beta, x, w, PetscDTGaussQuadratureNewton_Internal);CHKERRQ(ierr); 172594e21283SToby Isaac if (a != -1. || b != 1.) { /* shift */ 172694e21283SToby Isaac for (i = 0; i < npoints; i++) { 172794e21283SToby Isaac x[i] = (x[i] + 1.) * ((b - a) / 2.) + a; 172894e21283SToby Isaac w[i] *= (b - a) / 2.; 172994e21283SToby Isaac } 173094e21283SToby Isaac } 1731e6a796c3SToby Isaac PetscFunctionReturn(0); 1732e6a796c3SToby Isaac } 1733e6a796c3SToby Isaac 1734e6a796c3SToby Isaac static PetscErrorCode PetscDTGaussLobattoJacobiQuadrature_Internal(PetscInt npoints,PetscReal alpha, PetscReal beta, PetscReal x[], PetscReal w[], PetscBool newton) 1735e6a796c3SToby Isaac { 1736e6a796c3SToby Isaac PetscInt i; 1737e6a796c3SToby Isaac PetscErrorCode ierr; 1738e6a796c3SToby Isaac 1739e6a796c3SToby Isaac PetscFunctionBegin; 17402c71b3e2SJacob Faibussowitsch PetscCheckFalse(npoints < 2,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Number of points must be positive"); 1741e6a796c3SToby Isaac /* If asking for a 1D Lobatto point, just return the non-Lobatto 1D point */ 17422c71b3e2SJacob Faibussowitsch PetscCheckFalse(alpha <= -1.,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"alpha must be > -1."); 17432c71b3e2SJacob Faibussowitsch PetscCheckFalse(beta <= -1.,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"beta must be > -1."); 1744e6a796c3SToby Isaac 1745e6a796c3SToby Isaac x[0] = -1.; 1746e6a796c3SToby Isaac x[npoints-1] = 1.; 174794e21283SToby Isaac if (npoints > 2) { 174894e21283SToby Isaac ierr = PetscDTGaussJacobiQuadrature_Internal(npoints-2, alpha+1., beta+1., &x[1], &w[1], newton);CHKERRQ(ierr); 174994e21283SToby Isaac } 1750e6a796c3SToby Isaac for (i = 1; i < npoints - 1; i++) { 1751e6a796c3SToby Isaac w[i] /= (1. - x[i]*x[i]); 1752e6a796c3SToby Isaac } 1753e6a796c3SToby Isaac ierr = PetscDTGaussLobattoJacobiEndweights_Internal(npoints, alpha, beta, &w[0], &w[npoints-1]);CHKERRQ(ierr); 1754e6a796c3SToby Isaac PetscFunctionReturn(0); 1755e6a796c3SToby Isaac } 1756e6a796c3SToby Isaac 175737045ce4SJed Brown /*@ 175894e21283SToby Isaac PetscDTGaussLobattoJacobiQuadrature - quadrature for the interval [a, b] with the weight function 175994e21283SToby Isaac $(x-a)^\alpha (x-b)^\beta$, with endpoints a and b included as quadrature points. 176094e21283SToby Isaac 176194e21283SToby Isaac Not collective 176294e21283SToby Isaac 176394e21283SToby Isaac Input Parameters: 176494e21283SToby Isaac + npoints - the number of points in the quadrature rule 176594e21283SToby Isaac . a - the left endpoint of the interval 176694e21283SToby Isaac . b - the right endpoint of the interval 176794e21283SToby Isaac . alpha - the left exponent 176894e21283SToby Isaac - beta - the right exponent 176994e21283SToby Isaac 177094e21283SToby Isaac Output Parameters: 177194e21283SToby Isaac + x - array of length npoints, the locations of the quadrature points 177294e21283SToby Isaac - w - array of length npoints, the weights of the quadrature points 177394e21283SToby Isaac 177494e21283SToby Isaac Level: intermediate 177594e21283SToby Isaac 177694e21283SToby Isaac Note: this quadrature rule is exact for polynomials up to degree 2*npoints - 3. 177794e21283SToby Isaac @*/ 177894e21283SToby Isaac PetscErrorCode PetscDTGaussLobattoJacobiQuadrature(PetscInt npoints,PetscReal a, PetscReal b, PetscReal alpha, PetscReal beta, PetscReal x[], PetscReal w[]) 177994e21283SToby Isaac { 178094e21283SToby Isaac PetscInt i; 178194e21283SToby Isaac PetscErrorCode ierr; 178294e21283SToby Isaac 178394e21283SToby Isaac PetscFunctionBegin; 178494e21283SToby Isaac ierr = PetscDTGaussLobattoJacobiQuadrature_Internal(npoints, alpha, beta, x, w, PetscDTGaussQuadratureNewton_Internal);CHKERRQ(ierr); 178594e21283SToby Isaac if (a != -1. || b != 1.) { /* shift */ 178694e21283SToby Isaac for (i = 0; i < npoints; i++) { 178794e21283SToby Isaac x[i] = (x[i] + 1.) * ((b - a) / 2.) + a; 178894e21283SToby Isaac w[i] *= (b - a) / 2.; 178994e21283SToby Isaac } 179094e21283SToby Isaac } 179194e21283SToby Isaac PetscFunctionReturn(0); 179294e21283SToby Isaac } 179394e21283SToby Isaac 179494e21283SToby Isaac /*@ 1795e6a796c3SToby Isaac PetscDTGaussQuadrature - create Gauss-Legendre quadrature 179637045ce4SJed Brown 179737045ce4SJed Brown Not Collective 179837045ce4SJed Brown 17994165533cSJose E. Roman Input Parameters: 180037045ce4SJed Brown + npoints - number of points 180137045ce4SJed Brown . a - left end of interval (often-1) 180237045ce4SJed Brown - b - right end of interval (often +1) 180337045ce4SJed Brown 18044165533cSJose E. Roman Output Parameters: 180537045ce4SJed Brown + x - quadrature points 180637045ce4SJed Brown - w - quadrature weights 180737045ce4SJed Brown 180837045ce4SJed Brown Level: intermediate 180937045ce4SJed Brown 181037045ce4SJed Brown References: 1811606c0280SSatish Balay . * - Golub and Welsch, Calculation of Quadrature Rules, Math. Comp. 23(106), 1969. 181237045ce4SJed Brown 181337045ce4SJed Brown .seealso: PetscDTLegendreEval() 181437045ce4SJed Brown @*/ 181537045ce4SJed Brown PetscErrorCode PetscDTGaussQuadrature(PetscInt npoints,PetscReal a,PetscReal b,PetscReal *x,PetscReal *w) 181637045ce4SJed Brown { 181737045ce4SJed Brown PetscInt i; 1818e6a796c3SToby Isaac PetscErrorCode ierr; 181937045ce4SJed Brown 182037045ce4SJed Brown PetscFunctionBegin; 182194e21283SToby Isaac ierr = PetscDTGaussJacobiQuadrature_Internal(npoints, 0., 0., x, w, PetscDTGaussQuadratureNewton_Internal);CHKERRQ(ierr); 182294e21283SToby Isaac if (a != -1. || b != 1.) { /* shift */ 182337045ce4SJed Brown for (i = 0; i < npoints; i++) { 1824e6a796c3SToby Isaac x[i] = (x[i] + 1.) * ((b - a) / 2.) + a; 1825e6a796c3SToby Isaac w[i] *= (b - a) / 2.; 182637045ce4SJed Brown } 182737045ce4SJed Brown } 182837045ce4SJed Brown PetscFunctionReturn(0); 182937045ce4SJed Brown } 1830194825f6SJed Brown 18318272889dSSatish Balay /*@C 18328272889dSSatish Balay PetscDTGaussLobattoLegendreQuadrature - creates a set of the locations and weights of the Gauss-Lobatto-Legendre 18338272889dSSatish Balay nodes of a given size on the domain [-1,1] 18348272889dSSatish Balay 18358272889dSSatish Balay Not Collective 18368272889dSSatish Balay 1837d8d19677SJose E. Roman Input Parameters: 18388272889dSSatish Balay + n - number of grid nodes 1839f2e8fe4dShannah_mairs - type - PETSCGAUSSLOBATTOLEGENDRE_VIA_LINEAR_ALGEBRA or PETSCGAUSSLOBATTOLEGENDRE_VIA_NEWTON 18408272889dSSatish Balay 18414165533cSJose E. Roman Output Parameters: 18428272889dSSatish Balay + x - quadrature points 18438272889dSSatish Balay - w - quadrature weights 18448272889dSSatish Balay 18458272889dSSatish Balay Notes: 18468272889dSSatish Balay For n > 30 the Newton approach computes duplicate (incorrect) values for some nodes because the initial guess is apparently not 18478272889dSSatish Balay close enough to the desired solution 18488272889dSSatish Balay 18498272889dSSatish Balay These are useful for implementing spectral methods based on Gauss-Lobatto-Legendre (GLL) nodes 18508272889dSSatish Balay 1851a8d69d7bSBarry Smith 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 18528272889dSSatish Balay 18538272889dSSatish Balay Level: intermediate 18548272889dSSatish Balay 18558272889dSSatish Balay .seealso: PetscDTGaussQuadrature() 18568272889dSSatish Balay 18578272889dSSatish Balay @*/ 1858916e780bShannah_mairs PetscErrorCode PetscDTGaussLobattoLegendreQuadrature(PetscInt npoints,PetscGaussLobattoLegendreCreateType type,PetscReal *x,PetscReal *w) 18598272889dSSatish Balay { 1860e6a796c3SToby Isaac PetscBool newton; 18618272889dSSatish Balay PetscErrorCode ierr; 18628272889dSSatish Balay 18638272889dSSatish Balay PetscFunctionBegin; 18642c71b3e2SJacob Faibussowitsch PetscCheckFalse(npoints < 2,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Must provide at least 2 grid points per element"); 186594e21283SToby Isaac newton = (PetscBool) (type == PETSCGAUSSLOBATTOLEGENDRE_VIA_NEWTON); 1866e6a796c3SToby Isaac ierr = PetscDTGaussLobattoJacobiQuadrature_Internal(npoints, 0., 0., x, w, newton);CHKERRQ(ierr); 18678272889dSSatish Balay PetscFunctionReturn(0); 18688272889dSSatish Balay } 18698272889dSSatish Balay 1870744bafbcSMatthew G. Knepley /*@ 1871744bafbcSMatthew G. Knepley PetscDTGaussTensorQuadrature - creates a tensor-product Gauss quadrature 1872744bafbcSMatthew G. Knepley 1873744bafbcSMatthew G. Knepley Not Collective 1874744bafbcSMatthew G. Knepley 18754165533cSJose E. Roman Input Parameters: 1876744bafbcSMatthew G. Knepley + dim - The spatial dimension 1877a6b92713SMatthew G. Knepley . Nc - The number of components 1878744bafbcSMatthew G. Knepley . npoints - number of points in one dimension 1879744bafbcSMatthew G. Knepley . a - left end of interval (often-1) 1880744bafbcSMatthew G. Knepley - b - right end of interval (often +1) 1881744bafbcSMatthew G. Knepley 18824165533cSJose E. Roman Output Parameter: 1883744bafbcSMatthew G. Knepley . q - A PetscQuadrature object 1884744bafbcSMatthew G. Knepley 1885744bafbcSMatthew G. Knepley Level: intermediate 1886744bafbcSMatthew G. Knepley 1887744bafbcSMatthew G. Knepley .seealso: PetscDTGaussQuadrature(), PetscDTLegendreEval() 1888744bafbcSMatthew G. Knepley @*/ 1889a6b92713SMatthew G. Knepley PetscErrorCode PetscDTGaussTensorQuadrature(PetscInt dim, PetscInt Nc, PetscInt npoints, PetscReal a, PetscReal b, PetscQuadrature *q) 1890744bafbcSMatthew G. Knepley { 1891a6b92713SMatthew G. Knepley PetscInt totpoints = dim > 1 ? dim > 2 ? npoints*PetscSqr(npoints) : PetscSqr(npoints) : npoints, i, j, k, c; 1892744bafbcSMatthew G. Knepley PetscReal *x, *w, *xw, *ww; 1893744bafbcSMatthew G. Knepley PetscErrorCode ierr; 1894744bafbcSMatthew G. Knepley 1895744bafbcSMatthew G. Knepley PetscFunctionBegin; 1896744bafbcSMatthew G. Knepley ierr = PetscMalloc1(totpoints*dim,&x);CHKERRQ(ierr); 1897a6b92713SMatthew G. Knepley ierr = PetscMalloc1(totpoints*Nc,&w);CHKERRQ(ierr); 1898744bafbcSMatthew G. Knepley /* Set up the Golub-Welsch system */ 1899744bafbcSMatthew G. Knepley switch (dim) { 1900744bafbcSMatthew G. Knepley case 0: 1901744bafbcSMatthew G. Knepley ierr = PetscFree(x);CHKERRQ(ierr); 1902744bafbcSMatthew G. Knepley ierr = PetscFree(w);CHKERRQ(ierr); 1903744bafbcSMatthew G. Knepley ierr = PetscMalloc1(1, &x);CHKERRQ(ierr); 1904a6b92713SMatthew G. Knepley ierr = PetscMalloc1(Nc, &w);CHKERRQ(ierr); 1905744bafbcSMatthew G. Knepley x[0] = 0.0; 1906a6b92713SMatthew G. Knepley for (c = 0; c < Nc; ++c) w[c] = 1.0; 1907744bafbcSMatthew G. Knepley break; 1908744bafbcSMatthew G. Knepley case 1: 1909a6b92713SMatthew G. Knepley ierr = PetscMalloc1(npoints,&ww);CHKERRQ(ierr); 1910a6b92713SMatthew G. Knepley ierr = PetscDTGaussQuadrature(npoints, a, b, x, ww);CHKERRQ(ierr); 1911a6b92713SMatthew G. Knepley for (i = 0; i < npoints; ++i) for (c = 0; c < Nc; ++c) w[i*Nc+c] = ww[i]; 1912a6b92713SMatthew G. Knepley ierr = PetscFree(ww);CHKERRQ(ierr); 1913744bafbcSMatthew G. Knepley break; 1914744bafbcSMatthew G. Knepley case 2: 1915744bafbcSMatthew G. Knepley ierr = PetscMalloc2(npoints,&xw,npoints,&ww);CHKERRQ(ierr); 1916744bafbcSMatthew G. Knepley ierr = PetscDTGaussQuadrature(npoints, a, b, xw, ww);CHKERRQ(ierr); 1917744bafbcSMatthew G. Knepley for (i = 0; i < npoints; ++i) { 1918744bafbcSMatthew G. Knepley for (j = 0; j < npoints; ++j) { 1919744bafbcSMatthew G. Knepley x[(i*npoints+j)*dim+0] = xw[i]; 1920744bafbcSMatthew G. Knepley x[(i*npoints+j)*dim+1] = xw[j]; 1921a6b92713SMatthew G. Knepley for (c = 0; c < Nc; ++c) w[(i*npoints+j)*Nc+c] = ww[i] * ww[j]; 1922744bafbcSMatthew G. Knepley } 1923744bafbcSMatthew G. Knepley } 1924744bafbcSMatthew G. Knepley ierr = PetscFree2(xw,ww);CHKERRQ(ierr); 1925744bafbcSMatthew G. Knepley break; 1926744bafbcSMatthew G. Knepley case 3: 1927744bafbcSMatthew G. Knepley ierr = PetscMalloc2(npoints,&xw,npoints,&ww);CHKERRQ(ierr); 1928744bafbcSMatthew G. Knepley ierr = PetscDTGaussQuadrature(npoints, a, b, xw, ww);CHKERRQ(ierr); 1929744bafbcSMatthew G. Knepley for (i = 0; i < npoints; ++i) { 1930744bafbcSMatthew G. Knepley for (j = 0; j < npoints; ++j) { 1931744bafbcSMatthew G. Knepley for (k = 0; k < npoints; ++k) { 1932744bafbcSMatthew G. Knepley x[((i*npoints+j)*npoints+k)*dim+0] = xw[i]; 1933744bafbcSMatthew G. Knepley x[((i*npoints+j)*npoints+k)*dim+1] = xw[j]; 1934744bafbcSMatthew G. Knepley x[((i*npoints+j)*npoints+k)*dim+2] = xw[k]; 1935a6b92713SMatthew G. Knepley for (c = 0; c < Nc; ++c) w[((i*npoints+j)*npoints+k)*Nc+c] = ww[i] * ww[j] * ww[k]; 1936744bafbcSMatthew G. Knepley } 1937744bafbcSMatthew G. Knepley } 1938744bafbcSMatthew G. Knepley } 1939744bafbcSMatthew G. Knepley ierr = PetscFree2(xw,ww);CHKERRQ(ierr); 1940744bafbcSMatthew G. Knepley break; 1941744bafbcSMatthew G. Knepley default: 194298921bdaSJacob Faibussowitsch SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct quadrature rule for dimension %d", dim); 1943744bafbcSMatthew G. Knepley } 1944744bafbcSMatthew G. Knepley ierr = PetscQuadratureCreate(PETSC_COMM_SELF, q);CHKERRQ(ierr); 19452f5fb066SToby Isaac ierr = PetscQuadratureSetOrder(*q, 2*npoints-1);CHKERRQ(ierr); 1946a6b92713SMatthew G. Knepley ierr = PetscQuadratureSetData(*q, dim, Nc, totpoints, x, w);CHKERRQ(ierr); 1947d9bac1caSLisandro Dalcin ierr = PetscObjectChangeTypeName((PetscObject)*q,"GaussTensor");CHKERRQ(ierr); 1948744bafbcSMatthew G. Knepley PetscFunctionReturn(0); 1949744bafbcSMatthew G. Knepley } 1950744bafbcSMatthew G. Knepley 1951f5f57ec0SBarry Smith /*@ 1952e6a796c3SToby Isaac PetscDTStroudConicalQuadrature - create Stroud conical quadrature for a simplex 1953494e7359SMatthew G. Knepley 1954494e7359SMatthew G. Knepley Not Collective 1955494e7359SMatthew G. Knepley 19564165533cSJose E. Roman Input Parameters: 1957494e7359SMatthew G. Knepley + dim - The simplex dimension 1958a6b92713SMatthew G. Knepley . Nc - The number of components 1959dcce0ee2SMatthew G. Knepley . npoints - The number of points in one dimension 1960494e7359SMatthew G. Knepley . a - left end of interval (often-1) 1961494e7359SMatthew G. Knepley - b - right end of interval (often +1) 1962494e7359SMatthew G. Knepley 19634165533cSJose E. Roman Output Parameter: 1964552aa4f7SMatthew G. Knepley . q - A PetscQuadrature object 1965494e7359SMatthew G. Knepley 1966494e7359SMatthew G. Knepley Level: intermediate 1967494e7359SMatthew G. Knepley 1968494e7359SMatthew G. Knepley References: 1969606c0280SSatish Balay . * - Karniadakis and Sherwin. FIAT 1970494e7359SMatthew G. Knepley 1971e6a796c3SToby Isaac Note: For dim == 1, this is Gauss-Legendre quadrature 1972e6a796c3SToby Isaac 1973744bafbcSMatthew G. Knepley .seealso: PetscDTGaussTensorQuadrature(), PetscDTGaussQuadrature() 1974494e7359SMatthew G. Knepley @*/ 1975e6a796c3SToby Isaac PetscErrorCode PetscDTStroudConicalQuadrature(PetscInt dim, PetscInt Nc, PetscInt npoints, PetscReal a, PetscReal b, PetscQuadrature *q) 1976494e7359SMatthew G. Knepley { 1977fbdc3dfeSToby Isaac PetscInt totprev, totrem; 1978fbdc3dfeSToby Isaac PetscInt totpoints; 1979fbdc3dfeSToby Isaac PetscReal *p1, *w1; 1980fbdc3dfeSToby Isaac PetscReal *x, *w; 1981fbdc3dfeSToby Isaac PetscInt i, j, k, l, m, pt, c; 1982fbdc3dfeSToby Isaac PetscErrorCode ierr; 1983494e7359SMatthew G. Knepley 1984494e7359SMatthew G. Knepley PetscFunctionBegin; 19852c71b3e2SJacob Faibussowitsch PetscCheckFalse((a != -1.0) || (b != 1.0),PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must use default internal right now"); 1986fbdc3dfeSToby Isaac totpoints = 1; 1987fbdc3dfeSToby Isaac for (i = 0, totpoints = 1; i < dim; i++) totpoints *= npoints; 1988dcce0ee2SMatthew G. Knepley ierr = PetscMalloc1(totpoints*dim, &x);CHKERRQ(ierr); 1989dcce0ee2SMatthew G. Knepley ierr = PetscMalloc1(totpoints*Nc, &w);CHKERRQ(ierr); 1990fbdc3dfeSToby Isaac ierr = PetscMalloc2(npoints, &p1, npoints, &w1);CHKERRQ(ierr); 1991fbdc3dfeSToby Isaac for (i = 0; i < totpoints*Nc; i++) w[i] = 1.; 1992fbdc3dfeSToby Isaac for (i = 0, totprev = 1, totrem = totpoints / npoints; i < dim; i++) { 1993fbdc3dfeSToby Isaac PetscReal mul; 1994fbdc3dfeSToby Isaac 1995fbdc3dfeSToby Isaac mul = PetscPowReal(2.,-i); 1996fbdc3dfeSToby Isaac ierr = PetscDTGaussJacobiQuadrature(npoints, -1., 1., i, 0.0, p1, w1);CHKERRQ(ierr); 1997fbdc3dfeSToby Isaac for (pt = 0, l = 0; l < totprev; l++) { 1998fbdc3dfeSToby Isaac for (j = 0; j < npoints; j++) { 1999fbdc3dfeSToby Isaac for (m = 0; m < totrem; m++, pt++) { 2000fbdc3dfeSToby Isaac for (k = 0; k < i; k++) x[pt*dim+k] = (x[pt*dim+k]+1.)*(1.-p1[j])*0.5 - 1.; 2001fbdc3dfeSToby Isaac x[pt * dim + i] = p1[j]; 2002fbdc3dfeSToby Isaac for (c = 0; c < Nc; c++) w[pt*Nc + c] *= mul * w1[j]; 2003494e7359SMatthew G. Knepley } 2004494e7359SMatthew G. Knepley } 2005494e7359SMatthew G. Knepley } 2006fbdc3dfeSToby Isaac totprev *= npoints; 2007fbdc3dfeSToby Isaac totrem /= npoints; 2008494e7359SMatthew G. Knepley } 2009fbdc3dfeSToby Isaac ierr = PetscFree2(p1, w1);CHKERRQ(ierr); 201021454ff5SMatthew G. Knepley ierr = PetscQuadratureCreate(PETSC_COMM_SELF, q);CHKERRQ(ierr); 20112f5fb066SToby Isaac ierr = PetscQuadratureSetOrder(*q, 2*npoints-1);CHKERRQ(ierr); 2012dcce0ee2SMatthew G. Knepley ierr = PetscQuadratureSetData(*q, dim, Nc, totpoints, x, w);CHKERRQ(ierr); 2013fbdc3dfeSToby Isaac ierr = PetscObjectChangeTypeName((PetscObject)*q,"StroudConical");CHKERRQ(ierr); 2014494e7359SMatthew G. Knepley PetscFunctionReturn(0); 2015494e7359SMatthew G. Knepley } 2016494e7359SMatthew G. Knepley 2017f5f57ec0SBarry Smith /*@ 2018b3c0f97bSTom Klotz PetscDTTanhSinhTensorQuadrature - create tanh-sinh quadrature for a tensor product cell 2019b3c0f97bSTom Klotz 2020b3c0f97bSTom Klotz Not Collective 2021b3c0f97bSTom Klotz 20224165533cSJose E. Roman Input Parameters: 2023b3c0f97bSTom Klotz + dim - The cell dimension 2024b3c0f97bSTom Klotz . level - The number of points in one dimension, 2^l 2025b3c0f97bSTom Klotz . a - left end of interval (often-1) 2026b3c0f97bSTom Klotz - b - right end of interval (often +1) 2027b3c0f97bSTom Klotz 20284165533cSJose E. Roman Output Parameter: 2029b3c0f97bSTom Klotz . q - A PetscQuadrature object 2030b3c0f97bSTom Klotz 2031b3c0f97bSTom Klotz Level: intermediate 2032b3c0f97bSTom Klotz 2033b3c0f97bSTom Klotz .seealso: PetscDTGaussTensorQuadrature() 2034b3c0f97bSTom Klotz @*/ 2035b3c0f97bSTom Klotz PetscErrorCode PetscDTTanhSinhTensorQuadrature(PetscInt dim, PetscInt level, PetscReal a, PetscReal b, PetscQuadrature *q) 2036b3c0f97bSTom Klotz { 2037b3c0f97bSTom Klotz const PetscInt p = 16; /* Digits of precision in the evaluation */ 2038b3c0f97bSTom Klotz const PetscReal alpha = (b-a)/2.; /* Half-width of the integration interval */ 2039b3c0f97bSTom Klotz const PetscReal beta = (b+a)/2.; /* Center of the integration interval */ 2040b3c0f97bSTom Klotz const PetscReal h = PetscPowReal(2.0, -level); /* Step size, length between x_k */ 2041d84b4d08SMatthew G. Knepley PetscReal xk; /* Quadrature point x_k on reference domain [-1, 1] */ 2042b3c0f97bSTom Klotz PetscReal wk = 0.5*PETSC_PI; /* Quadrature weight at x_k */ 2043b3c0f97bSTom Klotz PetscReal *x, *w; 2044b3c0f97bSTom Klotz PetscInt K, k, npoints; 2045b3c0f97bSTom Klotz PetscErrorCode ierr; 2046b3c0f97bSTom Klotz 2047b3c0f97bSTom Klotz PetscFunctionBegin; 20482c71b3e2SJacob Faibussowitsch PetscCheckFalse(dim > 1,PETSC_COMM_SELF, PETSC_ERR_SUP, "Dimension %d not yet implemented", dim); 20492c71b3e2SJacob Faibussowitsch PetscCheckFalse(!level,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must give a number of significant digits"); 2050b3c0f97bSTom Klotz /* Find K such that the weights are < 32 digits of precision */ 2051b3c0f97bSTom Klotz for (K = 1; PetscAbsReal(PetscLog10Real(wk)) < 2*p; ++K) { 20529add2064SThomas Klotz wk = 0.5*h*PETSC_PI*PetscCoshReal(K*h)/PetscSqr(PetscCoshReal(0.5*PETSC_PI*PetscSinhReal(K*h))); 2053b3c0f97bSTom Klotz } 2054b3c0f97bSTom Klotz ierr = PetscQuadratureCreate(PETSC_COMM_SELF, q);CHKERRQ(ierr); 2055b3c0f97bSTom Klotz ierr = PetscQuadratureSetOrder(*q, 2*K+1);CHKERRQ(ierr); 2056b3c0f97bSTom Klotz npoints = 2*K-1; 2057b3c0f97bSTom Klotz ierr = PetscMalloc1(npoints*dim, &x);CHKERRQ(ierr); 2058b3c0f97bSTom Klotz ierr = PetscMalloc1(npoints, &w);CHKERRQ(ierr); 2059b3c0f97bSTom Klotz /* Center term */ 2060b3c0f97bSTom Klotz x[0] = beta; 2061b3c0f97bSTom Klotz w[0] = 0.5*alpha*PETSC_PI; 2062b3c0f97bSTom Klotz for (k = 1; k < K; ++k) { 20639add2064SThomas Klotz wk = 0.5*alpha*h*PETSC_PI*PetscCoshReal(k*h)/PetscSqr(PetscCoshReal(0.5*PETSC_PI*PetscSinhReal(k*h))); 20641118d4bcSLisandro Dalcin xk = PetscTanhReal(0.5*PETSC_PI*PetscSinhReal(k*h)); 2065b3c0f97bSTom Klotz x[2*k-1] = -alpha*xk+beta; 2066b3c0f97bSTom Klotz w[2*k-1] = wk; 2067b3c0f97bSTom Klotz x[2*k+0] = alpha*xk+beta; 2068b3c0f97bSTom Klotz w[2*k+0] = wk; 2069b3c0f97bSTom Klotz } 2070a6b92713SMatthew G. Knepley ierr = PetscQuadratureSetData(*q, dim, 1, npoints, x, w);CHKERRQ(ierr); 2071b3c0f97bSTom Klotz PetscFunctionReturn(0); 2072b3c0f97bSTom Klotz } 2073b3c0f97bSTom Klotz 2074d6685f55SMatthew G. Knepley PetscErrorCode PetscDTTanhSinhIntegrate(void (*func)(const PetscReal[], void *, PetscReal *), PetscReal a, PetscReal b, PetscInt digits, void *ctx, PetscReal *sol) 2075b3c0f97bSTom Klotz { 2076b3c0f97bSTom Klotz const PetscInt p = 16; /* Digits of precision in the evaluation */ 2077b3c0f97bSTom Klotz const PetscReal alpha = (b-a)/2.; /* Half-width of the integration interval */ 2078b3c0f97bSTom Klotz const PetscReal beta = (b+a)/2.; /* Center of the integration interval */ 2079b3c0f97bSTom Klotz PetscReal h = 1.0; /* Step size, length between x_k */ 2080b3c0f97bSTom Klotz PetscInt l = 0; /* Level of refinement, h = 2^{-l} */ 2081b3c0f97bSTom Klotz PetscReal osum = 0.0; /* Integral on last level */ 2082b3c0f97bSTom Klotz PetscReal psum = 0.0; /* Integral on the level before the last level */ 2083b3c0f97bSTom Klotz PetscReal sum; /* Integral on current level */ 2084446c295cSMatthew G. Knepley PetscReal yk; /* Quadrature point 1 - x_k on reference domain [-1, 1] */ 2085b3c0f97bSTom Klotz PetscReal lx, rx; /* Quadrature points to the left and right of 0 on the real domain [a, b] */ 2086b3c0f97bSTom Klotz PetscReal wk; /* Quadrature weight at x_k */ 2087b3c0f97bSTom Klotz PetscReal lval, rval; /* Terms in the quadature sum to the left and right of 0 */ 2088b3c0f97bSTom Klotz PetscInt d; /* Digits of precision in the integral */ 2089b3c0f97bSTom Klotz 2090b3c0f97bSTom Klotz PetscFunctionBegin; 20912c71b3e2SJacob Faibussowitsch PetscCheckFalse(digits <= 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must give a positive number of significant digits"); 2092b3c0f97bSTom Klotz /* Center term */ 2093d6685f55SMatthew G. Knepley func(&beta, ctx, &lval); 2094b3c0f97bSTom Klotz sum = 0.5*alpha*PETSC_PI*lval; 2095b3c0f97bSTom Klotz /* */ 2096b3c0f97bSTom Klotz do { 2097b3c0f97bSTom Klotz PetscReal lterm, rterm, maxTerm = 0.0, d1, d2, d3, d4; 2098b3c0f97bSTom Klotz PetscInt k = 1; 2099b3c0f97bSTom Klotz 2100b3c0f97bSTom Klotz ++l; 2101b3c0f97bSTom Klotz /* PetscPrintf(PETSC_COMM_SELF, "LEVEL %D sum: %15.15f\n", l, sum); */ 2102b3c0f97bSTom Klotz /* At each level of refinement, h --> h/2 and sum --> sum/2 */ 2103b3c0f97bSTom Klotz psum = osum; 2104b3c0f97bSTom Klotz osum = sum; 2105b3c0f97bSTom Klotz h *= 0.5; 2106b3c0f97bSTom Klotz sum *= 0.5; 2107b3c0f97bSTom Klotz do { 21089add2064SThomas Klotz wk = 0.5*h*PETSC_PI*PetscCoshReal(k*h)/PetscSqr(PetscCoshReal(0.5*PETSC_PI*PetscSinhReal(k*h))); 2109446c295cSMatthew G. Knepley yk = 1.0/(PetscExpReal(0.5*PETSC_PI*PetscSinhReal(k*h)) * PetscCoshReal(0.5*PETSC_PI*PetscSinhReal(k*h))); 2110446c295cSMatthew G. Knepley lx = -alpha*(1.0 - yk)+beta; 2111446c295cSMatthew G. Knepley rx = alpha*(1.0 - yk)+beta; 2112d6685f55SMatthew G. Knepley func(&lx, ctx, &lval); 2113d6685f55SMatthew G. Knepley func(&rx, ctx, &rval); 2114b3c0f97bSTom Klotz lterm = alpha*wk*lval; 2115b3c0f97bSTom Klotz maxTerm = PetscMax(PetscAbsReal(lterm), maxTerm); 2116b3c0f97bSTom Klotz sum += lterm; 2117b3c0f97bSTom Klotz rterm = alpha*wk*rval; 2118b3c0f97bSTom Klotz maxTerm = PetscMax(PetscAbsReal(rterm), maxTerm); 2119b3c0f97bSTom Klotz sum += rterm; 2120b3c0f97bSTom Klotz ++k; 2121b3c0f97bSTom Klotz /* Only need to evaluate every other point on refined levels */ 2122b3c0f97bSTom Klotz if (l != 1) ++k; 21239add2064SThomas Klotz } while (PetscAbsReal(PetscLog10Real(wk)) < p); /* Only need to evaluate sum until weights are < 32 digits of precision */ 2124b3c0f97bSTom Klotz 2125b3c0f97bSTom Klotz d1 = PetscLog10Real(PetscAbsReal(sum - osum)); 2126b3c0f97bSTom Klotz d2 = PetscLog10Real(PetscAbsReal(sum - psum)); 2127b3c0f97bSTom Klotz d3 = PetscLog10Real(maxTerm) - p; 212809d48545SBarry Smith if (PetscMax(PetscAbsReal(lterm), PetscAbsReal(rterm)) == 0.0) d4 = 0.0; 212909d48545SBarry Smith else d4 = PetscLog10Real(PetscMax(PetscAbsReal(lterm), PetscAbsReal(rterm))); 2130b3c0f97bSTom Klotz d = PetscAbsInt(PetscMin(0, PetscMax(PetscMax(PetscMax(PetscSqr(d1)/d2, 2*d1), d3), d4))); 21319add2064SThomas Klotz } while (d < digits && l < 12); 2132b3c0f97bSTom Klotz *sol = sum; 2133e510cb1fSThomas Klotz 2134b3c0f97bSTom Klotz PetscFunctionReturn(0); 2135b3c0f97bSTom Klotz } 2136b3c0f97bSTom Klotz 2137497880caSRichard Tran Mills #if defined(PETSC_HAVE_MPFR) 2138d6685f55SMatthew G. Knepley PetscErrorCode PetscDTTanhSinhIntegrateMPFR(void (*func)(const PetscReal[], void *, PetscReal *), PetscReal a, PetscReal b, PetscInt digits, void *ctx, PetscReal *sol) 213929f144ccSMatthew G. Knepley { 2140e510cb1fSThomas Klotz const PetscInt safetyFactor = 2; /* Calculate abcissa until 2*p digits */ 214129f144ccSMatthew G. Knepley PetscInt l = 0; /* Level of refinement, h = 2^{-l} */ 214229f144ccSMatthew G. Knepley mpfr_t alpha; /* Half-width of the integration interval */ 214329f144ccSMatthew G. Knepley mpfr_t beta; /* Center of the integration interval */ 214429f144ccSMatthew G. Knepley mpfr_t h; /* Step size, length between x_k */ 214529f144ccSMatthew G. Knepley mpfr_t osum; /* Integral on last level */ 214629f144ccSMatthew G. Knepley mpfr_t psum; /* Integral on the level before the last level */ 214729f144ccSMatthew G. Knepley mpfr_t sum; /* Integral on current level */ 214829f144ccSMatthew G. Knepley mpfr_t yk; /* Quadrature point 1 - x_k on reference domain [-1, 1] */ 214929f144ccSMatthew G. Knepley mpfr_t lx, rx; /* Quadrature points to the left and right of 0 on the real domain [a, b] */ 215029f144ccSMatthew G. Knepley mpfr_t wk; /* Quadrature weight at x_k */ 21511fbc92bbSMatthew G. Knepley PetscReal lval, rval, rtmp; /* Terms in the quadature sum to the left and right of 0 */ 215229f144ccSMatthew G. Knepley PetscInt d; /* Digits of precision in the integral */ 215329f144ccSMatthew G. Knepley mpfr_t pi2, kh, msinh, mcosh, maxTerm, curTerm, tmp; 215429f144ccSMatthew G. Knepley 215529f144ccSMatthew G. Knepley PetscFunctionBegin; 21562c71b3e2SJacob Faibussowitsch PetscCheckFalse(digits <= 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must give a positive number of significant digits"); 215729f144ccSMatthew G. Knepley /* Create high precision storage */ 2158c9f744b5SMatthew G. Knepley 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); 215929f144ccSMatthew G. Knepley /* Initialization */ 216029f144ccSMatthew G. Knepley mpfr_set_d(alpha, 0.5*(b-a), MPFR_RNDN); 216129f144ccSMatthew G. Knepley mpfr_set_d(beta, 0.5*(b+a), MPFR_RNDN); 216229f144ccSMatthew G. Knepley mpfr_set_d(osum, 0.0, MPFR_RNDN); 216329f144ccSMatthew G. Knepley mpfr_set_d(psum, 0.0, MPFR_RNDN); 216429f144ccSMatthew G. Knepley mpfr_set_d(h, 1.0, MPFR_RNDN); 216529f144ccSMatthew G. Knepley mpfr_const_pi(pi2, MPFR_RNDN); 216629f144ccSMatthew G. Knepley mpfr_mul_d(pi2, pi2, 0.5, MPFR_RNDN); 216729f144ccSMatthew G. Knepley /* Center term */ 21681fbc92bbSMatthew G. Knepley rtmp = 0.5*(b+a); 21691fbc92bbSMatthew G. Knepley func(&rtmp, ctx, &lval); 217029f144ccSMatthew G. Knepley mpfr_set(sum, pi2, MPFR_RNDN); 217129f144ccSMatthew G. Knepley mpfr_mul(sum, sum, alpha, MPFR_RNDN); 217229f144ccSMatthew G. Knepley mpfr_mul_d(sum, sum, lval, MPFR_RNDN); 217329f144ccSMatthew G. Knepley /* */ 217429f144ccSMatthew G. Knepley do { 217529f144ccSMatthew G. Knepley PetscReal d1, d2, d3, d4; 217629f144ccSMatthew G. Knepley PetscInt k = 1; 217729f144ccSMatthew G. Knepley 217829f144ccSMatthew G. Knepley ++l; 217929f144ccSMatthew G. Knepley mpfr_set_d(maxTerm, 0.0, MPFR_RNDN); 218029f144ccSMatthew G. Knepley /* PetscPrintf(PETSC_COMM_SELF, "LEVEL %D sum: %15.15f\n", l, sum); */ 218129f144ccSMatthew G. Knepley /* At each level of refinement, h --> h/2 and sum --> sum/2 */ 218229f144ccSMatthew G. Knepley mpfr_set(psum, osum, MPFR_RNDN); 218329f144ccSMatthew G. Knepley mpfr_set(osum, sum, MPFR_RNDN); 218429f144ccSMatthew G. Knepley mpfr_mul_d(h, h, 0.5, MPFR_RNDN); 218529f144ccSMatthew G. Knepley mpfr_mul_d(sum, sum, 0.5, MPFR_RNDN); 218629f144ccSMatthew G. Knepley do { 218729f144ccSMatthew G. Knepley mpfr_set_si(kh, k, MPFR_RNDN); 218829f144ccSMatthew G. Knepley mpfr_mul(kh, kh, h, MPFR_RNDN); 218929f144ccSMatthew G. Knepley /* Weight */ 219029f144ccSMatthew G. Knepley mpfr_set(wk, h, MPFR_RNDN); 219129f144ccSMatthew G. Knepley mpfr_sinh_cosh(msinh, mcosh, kh, MPFR_RNDN); 219229f144ccSMatthew G. Knepley mpfr_mul(msinh, msinh, pi2, MPFR_RNDN); 219329f144ccSMatthew G. Knepley mpfr_mul(mcosh, mcosh, pi2, MPFR_RNDN); 219429f144ccSMatthew G. Knepley mpfr_cosh(tmp, msinh, MPFR_RNDN); 219529f144ccSMatthew G. Knepley mpfr_sqr(tmp, tmp, MPFR_RNDN); 219629f144ccSMatthew G. Knepley mpfr_mul(wk, wk, mcosh, MPFR_RNDN); 219729f144ccSMatthew G. Knepley mpfr_div(wk, wk, tmp, MPFR_RNDN); 219829f144ccSMatthew G. Knepley /* Abscissa */ 219929f144ccSMatthew G. Knepley mpfr_set_d(yk, 1.0, MPFR_RNDZ); 220029f144ccSMatthew G. Knepley mpfr_cosh(tmp, msinh, MPFR_RNDN); 220129f144ccSMatthew G. Knepley mpfr_div(yk, yk, tmp, MPFR_RNDZ); 220229f144ccSMatthew G. Knepley mpfr_exp(tmp, msinh, MPFR_RNDN); 220329f144ccSMatthew G. Knepley mpfr_div(yk, yk, tmp, MPFR_RNDZ); 220429f144ccSMatthew G. Knepley /* Quadrature points */ 220529f144ccSMatthew G. Knepley mpfr_sub_d(lx, yk, 1.0, MPFR_RNDZ); 220629f144ccSMatthew G. Knepley mpfr_mul(lx, lx, alpha, MPFR_RNDU); 220729f144ccSMatthew G. Knepley mpfr_add(lx, lx, beta, MPFR_RNDU); 220829f144ccSMatthew G. Knepley mpfr_d_sub(rx, 1.0, yk, MPFR_RNDZ); 220929f144ccSMatthew G. Knepley mpfr_mul(rx, rx, alpha, MPFR_RNDD); 221029f144ccSMatthew G. Knepley mpfr_add(rx, rx, beta, MPFR_RNDD); 221129f144ccSMatthew G. Knepley /* Evaluation */ 22121fbc92bbSMatthew G. Knepley rtmp = mpfr_get_d(lx, MPFR_RNDU); 22131fbc92bbSMatthew G. Knepley func(&rtmp, ctx, &lval); 22141fbc92bbSMatthew G. Knepley rtmp = mpfr_get_d(rx, MPFR_RNDD); 22151fbc92bbSMatthew G. Knepley func(&rtmp, ctx, &rval); 221629f144ccSMatthew G. Knepley /* Update */ 221729f144ccSMatthew G. Knepley mpfr_mul(tmp, wk, alpha, MPFR_RNDN); 221829f144ccSMatthew G. Knepley mpfr_mul_d(tmp, tmp, lval, MPFR_RNDN); 221929f144ccSMatthew G. Knepley mpfr_add(sum, sum, tmp, MPFR_RNDN); 222029f144ccSMatthew G. Knepley mpfr_abs(tmp, tmp, MPFR_RNDN); 222129f144ccSMatthew G. Knepley mpfr_max(maxTerm, maxTerm, tmp, MPFR_RNDN); 222229f144ccSMatthew G. Knepley mpfr_set(curTerm, tmp, MPFR_RNDN); 222329f144ccSMatthew G. Knepley mpfr_mul(tmp, wk, alpha, MPFR_RNDN); 222429f144ccSMatthew G. Knepley mpfr_mul_d(tmp, tmp, rval, MPFR_RNDN); 222529f144ccSMatthew G. Knepley mpfr_add(sum, sum, tmp, MPFR_RNDN); 222629f144ccSMatthew G. Knepley mpfr_abs(tmp, tmp, MPFR_RNDN); 222729f144ccSMatthew G. Knepley mpfr_max(maxTerm, maxTerm, tmp, MPFR_RNDN); 222829f144ccSMatthew G. Knepley mpfr_max(curTerm, curTerm, tmp, MPFR_RNDN); 222929f144ccSMatthew G. Knepley ++k; 223029f144ccSMatthew G. Knepley /* Only need to evaluate every other point on refined levels */ 223129f144ccSMatthew G. Knepley if (l != 1) ++k; 223229f144ccSMatthew G. Knepley mpfr_log10(tmp, wk, MPFR_RNDN); 223329f144ccSMatthew G. Knepley mpfr_abs(tmp, tmp, MPFR_RNDN); 2234c9f744b5SMatthew G. Knepley } while (mpfr_get_d(tmp, MPFR_RNDN) < safetyFactor*digits); /* Only need to evaluate sum until weights are < 32 digits of precision */ 223529f144ccSMatthew G. Knepley mpfr_sub(tmp, sum, osum, MPFR_RNDN); 223629f144ccSMatthew G. Knepley mpfr_abs(tmp, tmp, MPFR_RNDN); 223729f144ccSMatthew G. Knepley mpfr_log10(tmp, tmp, MPFR_RNDN); 223829f144ccSMatthew G. Knepley d1 = mpfr_get_d(tmp, MPFR_RNDN); 223929f144ccSMatthew G. Knepley mpfr_sub(tmp, sum, psum, MPFR_RNDN); 224029f144ccSMatthew G. Knepley mpfr_abs(tmp, tmp, MPFR_RNDN); 224129f144ccSMatthew G. Knepley mpfr_log10(tmp, tmp, MPFR_RNDN); 224229f144ccSMatthew G. Knepley d2 = mpfr_get_d(tmp, MPFR_RNDN); 224329f144ccSMatthew G. Knepley mpfr_log10(tmp, maxTerm, MPFR_RNDN); 2244c9f744b5SMatthew G. Knepley d3 = mpfr_get_d(tmp, MPFR_RNDN) - digits; 224529f144ccSMatthew G. Knepley mpfr_log10(tmp, curTerm, MPFR_RNDN); 224629f144ccSMatthew G. Knepley d4 = mpfr_get_d(tmp, MPFR_RNDN); 224729f144ccSMatthew G. Knepley d = PetscAbsInt(PetscMin(0, PetscMax(PetscMax(PetscMax(PetscSqr(d1)/d2, 2*d1), d3), d4))); 2248b0649871SThomas Klotz } while (d < digits && l < 8); 224929f144ccSMatthew G. Knepley *sol = mpfr_get_d(sum, MPFR_RNDN); 225029f144ccSMatthew G. Knepley /* Cleanup */ 225129f144ccSMatthew G. Knepley mpfr_clears(alpha, beta, h, sum, osum, psum, yk, wk, lx, rx, tmp, maxTerm, curTerm, pi2, kh, msinh, mcosh, NULL); 225229f144ccSMatthew G. Knepley PetscFunctionReturn(0); 225329f144ccSMatthew G. Knepley } 2254d525116cSMatthew G. Knepley #else 2255fbfcfee5SBarry Smith 2256d6685f55SMatthew G. Knepley PetscErrorCode PetscDTTanhSinhIntegrateMPFR(void (*func)(const PetscReal[], void *, PetscReal *), PetscReal a, PetscReal b, PetscInt digits, void *ctx, PetscReal *sol) 2257d525116cSMatthew G. Knepley { 2258d525116cSMatthew G. Knepley SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "This method will not work without MPFR. Reconfigure using --download-mpfr --download-gmp"); 2259d525116cSMatthew G. Knepley } 226029f144ccSMatthew G. Knepley #endif 226129f144ccSMatthew G. Knepley 22622df84da0SMatthew G. Knepley /*@ 22632df84da0SMatthew G. Knepley PetscDTTensorQuadratureCreate - create the tensor product quadrature from two lower-dimensional quadratures 22642df84da0SMatthew G. Knepley 22652df84da0SMatthew G. Knepley Not Collective 22662df84da0SMatthew G. Knepley 22672df84da0SMatthew G. Knepley Input Parameters: 22682df84da0SMatthew G. Knepley + q1 - The first quadrature 22692df84da0SMatthew G. Knepley - q2 - The second quadrature 22702df84da0SMatthew G. Knepley 22712df84da0SMatthew G. Knepley Output Parameter: 22722df84da0SMatthew G. Knepley . q - A PetscQuadrature object 22732df84da0SMatthew G. Knepley 22742df84da0SMatthew G. Knepley Level: intermediate 22752df84da0SMatthew G. Knepley 22762df84da0SMatthew G. Knepley .seealso: PetscDTGaussTensorQuadrature() 22772df84da0SMatthew G. Knepley @*/ 22782df84da0SMatthew G. Knepley PetscErrorCode PetscDTTensorQuadratureCreate(PetscQuadrature q1, PetscQuadrature q2, PetscQuadrature *q) 22792df84da0SMatthew G. Knepley { 22802df84da0SMatthew G. Knepley const PetscReal *x1, *w1, *x2, *w2; 22812df84da0SMatthew G. Knepley PetscReal *x, *w; 22822df84da0SMatthew G. Knepley PetscInt dim1, Nc1, Np1, order1, qa, d1; 22832df84da0SMatthew G. Knepley PetscInt dim2, Nc2, Np2, order2, qb, d2; 22842df84da0SMatthew G. Knepley PetscInt dim, Nc, Np, order, qc, d; 22852df84da0SMatthew G. Knepley PetscErrorCode ierr; 22862df84da0SMatthew G. Knepley 22872df84da0SMatthew G. Knepley PetscFunctionBegin; 22882df84da0SMatthew G. Knepley PetscValidHeaderSpecific(q1, PETSCQUADRATURE_CLASSID, 1); 22892df84da0SMatthew G. Knepley PetscValidHeaderSpecific(q2, PETSCQUADRATURE_CLASSID, 2); 22902df84da0SMatthew G. Knepley PetscValidPointer(q, 3); 22912df84da0SMatthew G. Knepley ierr = PetscQuadratureGetOrder(q1, &order1);CHKERRQ(ierr); 22922df84da0SMatthew G. Knepley ierr = PetscQuadratureGetOrder(q2, &order2);CHKERRQ(ierr); 22932df84da0SMatthew G. Knepley PetscCheck(order1 == order2, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Order1 %" PetscInt_FMT " != %" PetscInt_FMT " Order2", order1, order2); 22942df84da0SMatthew G. Knepley ierr = PetscQuadratureGetData(q1, &dim1, &Nc1, &Np1, &x1, &w1);CHKERRQ(ierr); 22952df84da0SMatthew G. Knepley ierr = PetscQuadratureGetData(q2, &dim2, &Nc2, &Np2, &x2, &w2);CHKERRQ(ierr); 22962df84da0SMatthew G. Knepley PetscCheck(Nc1 == Nc2, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "NumComp1 %" PetscInt_FMT " != %" PetscInt_FMT " NumComp2", Nc1, Nc2); 22972df84da0SMatthew G. Knepley 22982df84da0SMatthew G. Knepley dim = dim1 + dim2; 22992df84da0SMatthew G. Knepley Nc = Nc1; 23002df84da0SMatthew G. Knepley Np = Np1 * Np2; 23012df84da0SMatthew G. Knepley order = order1; 23022df84da0SMatthew G. Knepley ierr = PetscQuadratureCreate(PETSC_COMM_SELF, q);CHKERRQ(ierr); 23032df84da0SMatthew G. Knepley ierr = PetscQuadratureSetOrder(*q, order);CHKERRQ(ierr); 23042df84da0SMatthew G. Knepley ierr = PetscMalloc1(Np*dim, &x);CHKERRQ(ierr); 23052df84da0SMatthew G. Knepley ierr = PetscMalloc1(Np, &w);CHKERRQ(ierr); 23062df84da0SMatthew G. Knepley for (qa = 0, qc = 0; qa < Np1; ++qa) { 23072df84da0SMatthew G. Knepley for (qb = 0; qb < Np2; ++qb, ++qc) { 23082df84da0SMatthew G. Knepley for (d1 = 0, d = 0; d1 < dim1; ++d1, ++d) { 23092df84da0SMatthew G. Knepley x[qc*dim+d] = x1[qa*dim1+d1]; 23102df84da0SMatthew G. Knepley } 23112df84da0SMatthew G. Knepley for (d2 = 0; d2 < dim2; ++d2, ++d) { 23122df84da0SMatthew G. Knepley x[qc*dim+d] = x2[qb*dim2+d2]; 23132df84da0SMatthew G. Knepley } 23142df84da0SMatthew G. Knepley w[qc] = w1[qa] * w2[qb]; 23152df84da0SMatthew G. Knepley } 23162df84da0SMatthew G. Knepley } 23172df84da0SMatthew G. Knepley ierr = PetscQuadratureSetData(*q, dim, Nc, Np, x, w);CHKERRQ(ierr); 23182df84da0SMatthew G. Knepley PetscFunctionReturn(0); 23192df84da0SMatthew G. Knepley } 23202df84da0SMatthew G. Knepley 2321194825f6SJed Brown /* Overwrites A. Can only handle full-rank problems with m>=n 2322194825f6SJed Brown * A in column-major format 2323194825f6SJed Brown * Ainv in row-major format 2324194825f6SJed Brown * tau has length m 2325194825f6SJed Brown * worksize must be >= max(1,n) 2326194825f6SJed Brown */ 2327194825f6SJed Brown static PetscErrorCode PetscDTPseudoInverseQR(PetscInt m,PetscInt mstride,PetscInt n,PetscReal *A_in,PetscReal *Ainv_out,PetscScalar *tau,PetscInt worksize,PetscScalar *work) 2328194825f6SJed Brown { 2329194825f6SJed Brown PetscErrorCode ierr; 2330194825f6SJed Brown PetscBLASInt M,N,K,lda,ldb,ldwork,info; 2331194825f6SJed Brown PetscScalar *A,*Ainv,*R,*Q,Alpha; 2332194825f6SJed Brown 2333194825f6SJed Brown PetscFunctionBegin; 2334194825f6SJed Brown #if defined(PETSC_USE_COMPLEX) 2335194825f6SJed Brown { 2336194825f6SJed Brown PetscInt i,j; 2337dcca6d9dSJed Brown ierr = PetscMalloc2(m*n,&A,m*n,&Ainv);CHKERRQ(ierr); 2338194825f6SJed Brown for (j=0; j<n; j++) { 2339194825f6SJed Brown for (i=0; i<m; i++) A[i+m*j] = A_in[i+mstride*j]; 2340194825f6SJed Brown } 2341194825f6SJed Brown mstride = m; 2342194825f6SJed Brown } 2343194825f6SJed Brown #else 2344194825f6SJed Brown A = A_in; 2345194825f6SJed Brown Ainv = Ainv_out; 2346194825f6SJed Brown #endif 2347194825f6SJed Brown 2348194825f6SJed Brown ierr = PetscBLASIntCast(m,&M);CHKERRQ(ierr); 2349194825f6SJed Brown ierr = PetscBLASIntCast(n,&N);CHKERRQ(ierr); 2350194825f6SJed Brown ierr = PetscBLASIntCast(mstride,&lda);CHKERRQ(ierr); 2351194825f6SJed Brown ierr = PetscBLASIntCast(worksize,&ldwork);CHKERRQ(ierr); 2352194825f6SJed Brown ierr = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr); 2353001a771dSBarry Smith PetscStackCallBLAS("LAPACKgeqrf",LAPACKgeqrf_(&M,&N,A,&lda,tau,work,&ldwork,&info)); 2354194825f6SJed Brown ierr = PetscFPTrapPop();CHKERRQ(ierr); 23552c71b3e2SJacob Faibussowitsch PetscCheckFalse(info,PETSC_COMM_SELF,PETSC_ERR_LIB,"xGEQRF error"); 2356194825f6SJed Brown R = A; /* Upper triangular part of A now contains R, the rest contains the elementary reflectors */ 2357194825f6SJed Brown 2358194825f6SJed Brown /* Extract an explicit representation of Q */ 2359194825f6SJed Brown Q = Ainv; 2360580bdb30SBarry Smith ierr = PetscArraycpy(Q,A,mstride*n);CHKERRQ(ierr); 2361194825f6SJed Brown K = N; /* full rank */ 2362c964aadfSJose E. Roman PetscStackCallBLAS("LAPACKorgqr",LAPACKorgqr_(&M,&N,&K,Q,&lda,tau,work,&ldwork,&info)); 23632c71b3e2SJacob Faibussowitsch PetscCheckFalse(info,PETSC_COMM_SELF,PETSC_ERR_LIB,"xORGQR/xUNGQR error"); 2364194825f6SJed Brown 2365194825f6SJed Brown /* Compute A^{-T} = (R^{-1} Q^T)^T = Q R^{-T} */ 2366194825f6SJed Brown Alpha = 1.0; 2367194825f6SJed Brown ldb = lda; 2368001a771dSBarry Smith PetscStackCallBLAS("BLAStrsm",BLAStrsm_("Right","Upper","ConjugateTranspose","NotUnitTriangular",&M,&N,&Alpha,R,&lda,Q,&ldb)); 2369194825f6SJed Brown /* Ainv is Q, overwritten with inverse */ 2370194825f6SJed Brown 2371194825f6SJed Brown #if defined(PETSC_USE_COMPLEX) 2372194825f6SJed Brown { 2373194825f6SJed Brown PetscInt i; 2374194825f6SJed Brown for (i=0; i<m*n; i++) Ainv_out[i] = PetscRealPart(Ainv[i]); 2375194825f6SJed Brown ierr = PetscFree2(A,Ainv);CHKERRQ(ierr); 2376194825f6SJed Brown } 2377194825f6SJed Brown #endif 2378194825f6SJed Brown PetscFunctionReturn(0); 2379194825f6SJed Brown } 2380194825f6SJed Brown 2381194825f6SJed Brown /* Computes integral of L_p' over intervals {(x0,x1),(x1,x2),...} */ 2382194825f6SJed Brown static PetscErrorCode PetscDTLegendreIntegrate(PetscInt ninterval,const PetscReal *x,PetscInt ndegree,const PetscInt *degrees,PetscBool Transpose,PetscReal *B) 2383194825f6SJed Brown { 2384194825f6SJed Brown PetscErrorCode ierr; 2385194825f6SJed Brown PetscReal *Bv; 2386194825f6SJed Brown PetscInt i,j; 2387194825f6SJed Brown 2388194825f6SJed Brown PetscFunctionBegin; 2389785e854fSJed Brown ierr = PetscMalloc1((ninterval+1)*ndegree,&Bv);CHKERRQ(ierr); 2390194825f6SJed Brown /* Point evaluation of L_p on all the source vertices */ 2391194825f6SJed Brown ierr = PetscDTLegendreEval(ninterval+1,x,ndegree,degrees,Bv,NULL,NULL);CHKERRQ(ierr); 2392194825f6SJed Brown /* Integral over each interval: \int_a^b L_p' = L_p(b)-L_p(a) */ 2393194825f6SJed Brown for (i=0; i<ninterval; i++) { 2394194825f6SJed Brown for (j=0; j<ndegree; j++) { 2395194825f6SJed Brown if (Transpose) B[i+ninterval*j] = Bv[(i+1)*ndegree+j] - Bv[i*ndegree+j]; 2396194825f6SJed Brown else B[i*ndegree+j] = Bv[(i+1)*ndegree+j] - Bv[i*ndegree+j]; 2397194825f6SJed Brown } 2398194825f6SJed Brown } 2399194825f6SJed Brown ierr = PetscFree(Bv);CHKERRQ(ierr); 2400194825f6SJed Brown PetscFunctionReturn(0); 2401194825f6SJed Brown } 2402194825f6SJed Brown 2403194825f6SJed Brown /*@ 2404194825f6SJed Brown PetscDTReconstructPoly - create matrix representing polynomial reconstruction using cell intervals and evaluation at target intervals 2405194825f6SJed Brown 2406194825f6SJed Brown Not Collective 2407194825f6SJed Brown 24084165533cSJose E. Roman Input Parameters: 2409194825f6SJed Brown + degree - degree of reconstruction polynomial 2410194825f6SJed Brown . nsource - number of source intervals 2411194825f6SJed Brown . sourcex - sorted coordinates of source cell boundaries (length nsource+1) 2412194825f6SJed Brown . ntarget - number of target intervals 2413194825f6SJed Brown - targetx - sorted coordinates of target cell boundaries (length ntarget+1) 2414194825f6SJed Brown 24154165533cSJose E. Roman Output Parameter: 2416194825f6SJed Brown . R - reconstruction matrix, utarget = sum_s R[t*nsource+s] * usource[s] 2417194825f6SJed Brown 2418194825f6SJed Brown Level: advanced 2419194825f6SJed Brown 2420194825f6SJed Brown .seealso: PetscDTLegendreEval() 2421194825f6SJed Brown @*/ 2422194825f6SJed Brown PetscErrorCode PetscDTReconstructPoly(PetscInt degree,PetscInt nsource,const PetscReal *sourcex,PetscInt ntarget,const PetscReal *targetx,PetscReal *R) 2423194825f6SJed Brown { 2424194825f6SJed Brown PetscErrorCode ierr; 2425194825f6SJed Brown PetscInt i,j,k,*bdegrees,worksize; 2426194825f6SJed Brown PetscReal xmin,xmax,center,hscale,*sourcey,*targety,*Bsource,*Bsinv,*Btarget; 2427194825f6SJed Brown PetscScalar *tau,*work; 2428194825f6SJed Brown 2429194825f6SJed Brown PetscFunctionBegin; 2430194825f6SJed Brown PetscValidRealPointer(sourcex,3); 2431194825f6SJed Brown PetscValidRealPointer(targetx,5); 2432194825f6SJed Brown PetscValidRealPointer(R,6); 24332c71b3e2SJacob Faibussowitsch PetscCheckFalse(degree >= nsource,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Reconstruction degree %D must be less than number of source intervals %D",degree,nsource); 243476bd3646SJed Brown if (PetscDefined(USE_DEBUG)) { 2435194825f6SJed Brown for (i=0; i<nsource; i++) { 24362c71b3e2SJacob Faibussowitsch PetscCheckFalse(sourcex[i] >= sourcex[i+1],PETSC_COMM_SELF,PETSC_ERR_ARG_CORRUPT,"Source interval %D has negative orientation (%g,%g)",i,(double)sourcex[i],(double)sourcex[i+1]); 2437194825f6SJed Brown } 2438194825f6SJed Brown for (i=0; i<ntarget; i++) { 24392c71b3e2SJacob Faibussowitsch PetscCheckFalse(targetx[i] >= targetx[i+1],PETSC_COMM_SELF,PETSC_ERR_ARG_CORRUPT,"Target interval %D has negative orientation (%g,%g)",i,(double)targetx[i],(double)targetx[i+1]); 2440194825f6SJed Brown } 244176bd3646SJed Brown } 2442194825f6SJed Brown xmin = PetscMin(sourcex[0],targetx[0]); 2443194825f6SJed Brown xmax = PetscMax(sourcex[nsource],targetx[ntarget]); 2444194825f6SJed Brown center = (xmin + xmax)/2; 2445194825f6SJed Brown hscale = (xmax - xmin)/2; 2446194825f6SJed Brown worksize = nsource; 2447dcca6d9dSJed Brown ierr = PetscMalloc4(degree+1,&bdegrees,nsource+1,&sourcey,nsource*(degree+1),&Bsource,worksize,&work);CHKERRQ(ierr); 2448dcca6d9dSJed Brown ierr = PetscMalloc4(nsource,&tau,nsource*(degree+1),&Bsinv,ntarget+1,&targety,ntarget*(degree+1),&Btarget);CHKERRQ(ierr); 2449194825f6SJed Brown for (i=0; i<=nsource; i++) sourcey[i] = (sourcex[i]-center)/hscale; 2450194825f6SJed Brown for (i=0; i<=degree; i++) bdegrees[i] = i+1; 2451194825f6SJed Brown ierr = PetscDTLegendreIntegrate(nsource,sourcey,degree+1,bdegrees,PETSC_TRUE,Bsource);CHKERRQ(ierr); 2452194825f6SJed Brown ierr = PetscDTPseudoInverseQR(nsource,nsource,degree+1,Bsource,Bsinv,tau,nsource,work);CHKERRQ(ierr); 2453194825f6SJed Brown for (i=0; i<=ntarget; i++) targety[i] = (targetx[i]-center)/hscale; 2454194825f6SJed Brown ierr = PetscDTLegendreIntegrate(ntarget,targety,degree+1,bdegrees,PETSC_FALSE,Btarget);CHKERRQ(ierr); 2455194825f6SJed Brown for (i=0; i<ntarget; i++) { 2456194825f6SJed Brown PetscReal rowsum = 0; 2457194825f6SJed Brown for (j=0; j<nsource; j++) { 2458194825f6SJed Brown PetscReal sum = 0; 2459194825f6SJed Brown for (k=0; k<degree+1; k++) { 2460194825f6SJed Brown sum += Btarget[i*(degree+1)+k] * Bsinv[k*nsource+j]; 2461194825f6SJed Brown } 2462194825f6SJed Brown R[i*nsource+j] = sum; 2463194825f6SJed Brown rowsum += sum; 2464194825f6SJed Brown } 2465194825f6SJed Brown for (j=0; j<nsource; j++) R[i*nsource+j] /= rowsum; /* normalize each row */ 2466194825f6SJed Brown } 2467194825f6SJed Brown ierr = PetscFree4(bdegrees,sourcey,Bsource,work);CHKERRQ(ierr); 2468194825f6SJed Brown ierr = PetscFree4(tau,Bsinv,targety,Btarget);CHKERRQ(ierr); 2469194825f6SJed Brown PetscFunctionReturn(0); 2470194825f6SJed Brown } 2471916e780bShannah_mairs 2472916e780bShannah_mairs /*@C 2473916e780bShannah_mairs PetscGaussLobattoLegendreIntegrate - Compute the L2 integral of a function on the GLL points 2474916e780bShannah_mairs 2475916e780bShannah_mairs Not Collective 2476916e780bShannah_mairs 2477d8d19677SJose E. Roman Input Parameters: 2478916e780bShannah_mairs + n - the number of GLL nodes 2479916e780bShannah_mairs . nodes - the GLL nodes 2480916e780bShannah_mairs . weights - the GLL weights 2481f0fc11ceSJed Brown - f - the function values at the nodes 2482916e780bShannah_mairs 2483916e780bShannah_mairs Output Parameter: 2484916e780bShannah_mairs . in - the value of the integral 2485916e780bShannah_mairs 2486916e780bShannah_mairs Level: beginner 2487916e780bShannah_mairs 2488916e780bShannah_mairs .seealso: PetscDTGaussLobattoLegendreQuadrature() 2489916e780bShannah_mairs 2490916e780bShannah_mairs @*/ 2491916e780bShannah_mairs PetscErrorCode PetscGaussLobattoLegendreIntegrate(PetscInt n,PetscReal *nodes,PetscReal *weights,const PetscReal *f,PetscReal *in) 2492916e780bShannah_mairs { 2493916e780bShannah_mairs PetscInt i; 2494916e780bShannah_mairs 2495916e780bShannah_mairs PetscFunctionBegin; 2496916e780bShannah_mairs *in = 0.; 2497916e780bShannah_mairs for (i=0; i<n; i++) { 2498916e780bShannah_mairs *in += f[i]*f[i]*weights[i]; 2499916e780bShannah_mairs } 2500916e780bShannah_mairs PetscFunctionReturn(0); 2501916e780bShannah_mairs } 2502916e780bShannah_mairs 2503916e780bShannah_mairs /*@C 2504916e780bShannah_mairs PetscGaussLobattoLegendreElementLaplacianCreate - computes the Laplacian for a single 1d GLL element 2505916e780bShannah_mairs 2506916e780bShannah_mairs Not Collective 2507916e780bShannah_mairs 2508d8d19677SJose E. Roman Input Parameters: 2509916e780bShannah_mairs + n - the number of GLL nodes 2510916e780bShannah_mairs . nodes - the GLL nodes 2511f0fc11ceSJed Brown - weights - the GLL weights 2512916e780bShannah_mairs 2513916e780bShannah_mairs Output Parameter: 2514916e780bShannah_mairs . A - the stiffness element 2515916e780bShannah_mairs 2516916e780bShannah_mairs Level: beginner 2517916e780bShannah_mairs 2518916e780bShannah_mairs Notes: 2519916e780bShannah_mairs Destroy this with PetscGaussLobattoLegendreElementLaplacianDestroy() 2520916e780bShannah_mairs 2521916e780bShannah_mairs 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) 2522916e780bShannah_mairs 2523916e780bShannah_mairs .seealso: PetscDTGaussLobattoLegendreQuadrature(), PetscGaussLobattoLegendreElementLaplacianDestroy() 2524916e780bShannah_mairs 2525916e780bShannah_mairs @*/ 2526916e780bShannah_mairs PetscErrorCode PetscGaussLobattoLegendreElementLaplacianCreate(PetscInt n,PetscReal *nodes,PetscReal *weights,PetscReal ***AA) 2527916e780bShannah_mairs { 2528916e780bShannah_mairs PetscReal **A; 2529916e780bShannah_mairs PetscErrorCode ierr; 2530916e780bShannah_mairs const PetscReal *gllnodes = nodes; 2531916e780bShannah_mairs const PetscInt p = n-1; 2532916e780bShannah_mairs PetscReal z0,z1,z2 = -1,x,Lpj,Lpr; 2533916e780bShannah_mairs PetscInt i,j,nn,r; 2534916e780bShannah_mairs 2535916e780bShannah_mairs PetscFunctionBegin; 2536916e780bShannah_mairs ierr = PetscMalloc1(n,&A);CHKERRQ(ierr); 2537916e780bShannah_mairs ierr = PetscMalloc1(n*n,&A[0]);CHKERRQ(ierr); 2538916e780bShannah_mairs for (i=1; i<n; i++) A[i] = A[i-1]+n; 2539916e780bShannah_mairs 2540916e780bShannah_mairs for (j=1; j<p; j++) { 2541916e780bShannah_mairs x = gllnodes[j]; 2542916e780bShannah_mairs z0 = 1.; 2543916e780bShannah_mairs z1 = x; 2544916e780bShannah_mairs for (nn=1; nn<p; nn++) { 2545916e780bShannah_mairs z2 = x*z1*(2.*((PetscReal)nn)+1.)/(((PetscReal)nn)+1.)-z0*(((PetscReal)nn)/(((PetscReal)nn)+1.)); 2546916e780bShannah_mairs z0 = z1; 2547916e780bShannah_mairs z1 = z2; 2548916e780bShannah_mairs } 2549916e780bShannah_mairs Lpj=z2; 2550916e780bShannah_mairs for (r=1; r<p; r++) { 2551916e780bShannah_mairs if (r == j) { 2552916e780bShannah_mairs A[j][j]=2./(3.*(1.-gllnodes[j]*gllnodes[j])*Lpj*Lpj); 2553916e780bShannah_mairs } else { 2554916e780bShannah_mairs x = gllnodes[r]; 2555916e780bShannah_mairs z0 = 1.; 2556916e780bShannah_mairs z1 = x; 2557916e780bShannah_mairs for (nn=1; nn<p; nn++) { 2558916e780bShannah_mairs z2 = x*z1*(2.*((PetscReal)nn)+1.)/(((PetscReal)nn)+1.)-z0*(((PetscReal)nn)/(((PetscReal)nn)+1.)); 2559916e780bShannah_mairs z0 = z1; 2560916e780bShannah_mairs z1 = z2; 2561916e780bShannah_mairs } 2562916e780bShannah_mairs Lpr = z2; 2563916e780bShannah_mairs A[r][j] = 4./(((PetscReal)p)*(((PetscReal)p)+1.)*Lpj*Lpr*(gllnodes[j]-gllnodes[r])*(gllnodes[j]-gllnodes[r])); 2564916e780bShannah_mairs } 2565916e780bShannah_mairs } 2566916e780bShannah_mairs } 2567916e780bShannah_mairs for (j=1; j<p+1; j++) { 2568916e780bShannah_mairs x = gllnodes[j]; 2569916e780bShannah_mairs z0 = 1.; 2570916e780bShannah_mairs z1 = x; 2571916e780bShannah_mairs for (nn=1; nn<p; nn++) { 2572916e780bShannah_mairs z2 = x*z1*(2.*((PetscReal)nn)+1.)/(((PetscReal)nn)+1.)-z0*(((PetscReal)nn)/(((PetscReal)nn)+1.)); 2573916e780bShannah_mairs z0 = z1; 2574916e780bShannah_mairs z1 = z2; 2575916e780bShannah_mairs } 2576916e780bShannah_mairs Lpj = z2; 2577916e780bShannah_mairs A[j][0] = 4.*PetscPowRealInt(-1.,p)/(((PetscReal)p)*(((PetscReal)p)+1.)*Lpj*(1.+gllnodes[j])*(1.+gllnodes[j])); 2578916e780bShannah_mairs A[0][j] = A[j][0]; 2579916e780bShannah_mairs } 2580916e780bShannah_mairs for (j=0; j<p; j++) { 2581916e780bShannah_mairs x = gllnodes[j]; 2582916e780bShannah_mairs z0 = 1.; 2583916e780bShannah_mairs z1 = x; 2584916e780bShannah_mairs for (nn=1; nn<p; nn++) { 2585916e780bShannah_mairs z2 = x*z1*(2.*((PetscReal)nn)+1.)/(((PetscReal)nn)+1.)-z0*(((PetscReal)nn)/(((PetscReal)nn)+1.)); 2586916e780bShannah_mairs z0 = z1; 2587916e780bShannah_mairs z1 = z2; 2588916e780bShannah_mairs } 2589916e780bShannah_mairs Lpj=z2; 2590916e780bShannah_mairs 2591916e780bShannah_mairs A[p][j] = 4./(((PetscReal)p)*(((PetscReal)p)+1.)*Lpj*(1.-gllnodes[j])*(1.-gllnodes[j])); 2592916e780bShannah_mairs A[j][p] = A[p][j]; 2593916e780bShannah_mairs } 2594916e780bShannah_mairs A[0][0]=0.5+(((PetscReal)p)*(((PetscReal)p)+1.)-2.)/6.; 2595916e780bShannah_mairs A[p][p]=A[0][0]; 2596916e780bShannah_mairs *AA = A; 2597916e780bShannah_mairs PetscFunctionReturn(0); 2598916e780bShannah_mairs } 2599916e780bShannah_mairs 2600916e780bShannah_mairs /*@C 2601916e780bShannah_mairs PetscGaussLobattoLegendreElementLaplacianDestroy - frees the Laplacian for a single 1d GLL element 2602916e780bShannah_mairs 2603916e780bShannah_mairs Not Collective 2604916e780bShannah_mairs 2605d8d19677SJose E. Roman Input Parameters: 2606916e780bShannah_mairs + n - the number of GLL nodes 2607916e780bShannah_mairs . nodes - the GLL nodes 2608916e780bShannah_mairs . weights - the GLL weightss 2609916e780bShannah_mairs - A - the stiffness element 2610916e780bShannah_mairs 2611916e780bShannah_mairs Level: beginner 2612916e780bShannah_mairs 2613916e780bShannah_mairs .seealso: PetscDTGaussLobattoLegendreQuadrature(), PetscGaussLobattoLegendreElementLaplacianCreate() 2614916e780bShannah_mairs 2615916e780bShannah_mairs @*/ 2616916e780bShannah_mairs PetscErrorCode PetscGaussLobattoLegendreElementLaplacianDestroy(PetscInt n,PetscReal *nodes,PetscReal *weights,PetscReal ***AA) 2617916e780bShannah_mairs { 2618916e780bShannah_mairs PetscErrorCode ierr; 2619916e780bShannah_mairs 2620916e780bShannah_mairs PetscFunctionBegin; 2621916e780bShannah_mairs ierr = PetscFree((*AA)[0]);CHKERRQ(ierr); 2622916e780bShannah_mairs ierr = PetscFree(*AA);CHKERRQ(ierr); 2623916e780bShannah_mairs *AA = NULL; 2624916e780bShannah_mairs PetscFunctionReturn(0); 2625916e780bShannah_mairs } 2626916e780bShannah_mairs 2627916e780bShannah_mairs /*@C 2628916e780bShannah_mairs PetscGaussLobattoLegendreElementGradientCreate - computes the gradient for a single 1d GLL element 2629916e780bShannah_mairs 2630916e780bShannah_mairs Not Collective 2631916e780bShannah_mairs 2632916e780bShannah_mairs Input Parameter: 2633916e780bShannah_mairs + n - the number of GLL nodes 2634916e780bShannah_mairs . nodes - the GLL nodes 2635916e780bShannah_mairs . weights - the GLL weights 2636916e780bShannah_mairs 2637d8d19677SJose E. Roman Output Parameters: 2638916e780bShannah_mairs . AA - the stiffness element 2639916e780bShannah_mairs - AAT - the transpose of AA (pass in NULL if you do not need this array) 2640916e780bShannah_mairs 2641916e780bShannah_mairs Level: beginner 2642916e780bShannah_mairs 2643916e780bShannah_mairs Notes: 2644916e780bShannah_mairs Destroy this with PetscGaussLobattoLegendreElementGradientDestroy() 2645916e780bShannah_mairs 2646916e780bShannah_mairs You can access entries in these arrays with AA[i][j] but in memory it is stored in contiguous memory, row oriented 2647916e780bShannah_mairs 2648916e780bShannah_mairs .seealso: PetscDTGaussLobattoLegendreQuadrature(), PetscGaussLobattoLegendreElementLaplacianDestroy() 2649916e780bShannah_mairs 2650916e780bShannah_mairs @*/ 2651916e780bShannah_mairs PetscErrorCode PetscGaussLobattoLegendreElementGradientCreate(PetscInt n,PetscReal *nodes,PetscReal *weights,PetscReal ***AA,PetscReal ***AAT) 2652916e780bShannah_mairs { 2653916e780bShannah_mairs PetscReal **A, **AT = NULL; 2654916e780bShannah_mairs PetscErrorCode ierr; 2655916e780bShannah_mairs const PetscReal *gllnodes = nodes; 2656916e780bShannah_mairs const PetscInt p = n-1; 2657e6a796c3SToby Isaac PetscReal Li, Lj,d0; 2658916e780bShannah_mairs PetscInt i,j; 2659916e780bShannah_mairs 2660916e780bShannah_mairs PetscFunctionBegin; 2661916e780bShannah_mairs ierr = PetscMalloc1(n,&A);CHKERRQ(ierr); 2662916e780bShannah_mairs ierr = PetscMalloc1(n*n,&A[0]);CHKERRQ(ierr); 2663916e780bShannah_mairs for (i=1; i<n; i++) A[i] = A[i-1]+n; 2664916e780bShannah_mairs 2665916e780bShannah_mairs if (AAT) { 2666916e780bShannah_mairs ierr = PetscMalloc1(n,&AT);CHKERRQ(ierr); 2667916e780bShannah_mairs ierr = PetscMalloc1(n*n,&AT[0]);CHKERRQ(ierr); 2668916e780bShannah_mairs for (i=1; i<n; i++) AT[i] = AT[i-1]+n; 2669916e780bShannah_mairs } 2670916e780bShannah_mairs 2671916e780bShannah_mairs if (n==1) {A[0][0] = 0.;} 2672916e780bShannah_mairs d0 = (PetscReal)p*((PetscReal)p+1.)/4.; 2673916e780bShannah_mairs for (i=0; i<n; i++) { 2674916e780bShannah_mairs for (j=0; j<n; j++) { 2675916e780bShannah_mairs A[i][j] = 0.; 2676e6a796c3SToby Isaac ierr = PetscDTComputeJacobi(0., 0., p, gllnodes[i], &Li);CHKERRQ(ierr); 2677e6a796c3SToby Isaac ierr = PetscDTComputeJacobi(0., 0., p, gllnodes[j], &Lj);CHKERRQ(ierr); 2678916e780bShannah_mairs if (i!=j) A[i][j] = Li/(Lj*(gllnodes[i]-gllnodes[j])); 2679916e780bShannah_mairs if ((j==i) && (i==0)) A[i][j] = -d0; 2680916e780bShannah_mairs if (j==i && i==p) A[i][j] = d0; 2681916e780bShannah_mairs if (AT) AT[j][i] = A[i][j]; 2682916e780bShannah_mairs } 2683916e780bShannah_mairs } 2684916e780bShannah_mairs if (AAT) *AAT = AT; 2685916e780bShannah_mairs *AA = A; 2686916e780bShannah_mairs PetscFunctionReturn(0); 2687916e780bShannah_mairs } 2688916e780bShannah_mairs 2689916e780bShannah_mairs /*@C 2690916e780bShannah_mairs PetscGaussLobattoLegendreElementGradientDestroy - frees the gradient for a single 1d GLL element obtained with PetscGaussLobattoLegendreElementGradientCreate() 2691916e780bShannah_mairs 2692916e780bShannah_mairs Not Collective 2693916e780bShannah_mairs 2694d8d19677SJose E. Roman Input Parameters: 2695916e780bShannah_mairs + n - the number of GLL nodes 2696916e780bShannah_mairs . nodes - the GLL nodes 2697916e780bShannah_mairs . weights - the GLL weights 2698916e780bShannah_mairs . AA - the stiffness element 2699916e780bShannah_mairs - AAT - the transpose of the element 2700916e780bShannah_mairs 2701916e780bShannah_mairs Level: beginner 2702916e780bShannah_mairs 2703916e780bShannah_mairs .seealso: PetscDTGaussLobattoLegendreQuadrature(), PetscGaussLobattoLegendreElementLaplacianCreate(), PetscGaussLobattoLegendreElementAdvectionCreate() 2704916e780bShannah_mairs 2705916e780bShannah_mairs @*/ 2706916e780bShannah_mairs PetscErrorCode PetscGaussLobattoLegendreElementGradientDestroy(PetscInt n,PetscReal *nodes,PetscReal *weights,PetscReal ***AA,PetscReal ***AAT) 2707916e780bShannah_mairs { 2708916e780bShannah_mairs PetscErrorCode ierr; 2709916e780bShannah_mairs 2710916e780bShannah_mairs PetscFunctionBegin; 2711916e780bShannah_mairs ierr = PetscFree((*AA)[0]);CHKERRQ(ierr); 2712916e780bShannah_mairs ierr = PetscFree(*AA);CHKERRQ(ierr); 2713916e780bShannah_mairs *AA = NULL; 2714916e780bShannah_mairs if (*AAT) { 2715916e780bShannah_mairs ierr = PetscFree((*AAT)[0]);CHKERRQ(ierr); 2716916e780bShannah_mairs ierr = PetscFree(*AAT);CHKERRQ(ierr); 2717916e780bShannah_mairs *AAT = NULL; 2718916e780bShannah_mairs } 2719916e780bShannah_mairs PetscFunctionReturn(0); 2720916e780bShannah_mairs } 2721916e780bShannah_mairs 2722916e780bShannah_mairs /*@C 2723916e780bShannah_mairs PetscGaussLobattoLegendreElementAdvectionCreate - computes the advection operator for a single 1d GLL element 2724916e780bShannah_mairs 2725916e780bShannah_mairs Not Collective 2726916e780bShannah_mairs 2727d8d19677SJose E. Roman Input Parameters: 2728916e780bShannah_mairs + n - the number of GLL nodes 2729916e780bShannah_mairs . nodes - the GLL nodes 2730f0fc11ceSJed Brown - weights - the GLL weightss 2731916e780bShannah_mairs 2732916e780bShannah_mairs Output Parameter: 2733916e780bShannah_mairs . AA - the stiffness element 2734916e780bShannah_mairs 2735916e780bShannah_mairs Level: beginner 2736916e780bShannah_mairs 2737916e780bShannah_mairs Notes: 2738916e780bShannah_mairs Destroy this with PetscGaussLobattoLegendreElementAdvectionDestroy() 2739916e780bShannah_mairs 2740916e780bShannah_mairs This is the same as the Gradient operator multiplied by the diagonal mass matrix 2741916e780bShannah_mairs 2742916e780bShannah_mairs You can access entries in this array with AA[i][j] but in memory it is stored in contiguous memory, row oriented 2743916e780bShannah_mairs 2744916e780bShannah_mairs .seealso: PetscDTGaussLobattoLegendreQuadrature(), PetscGaussLobattoLegendreElementLaplacianCreate(), PetscGaussLobattoLegendreElementAdvectionDestroy() 2745916e780bShannah_mairs 2746916e780bShannah_mairs @*/ 2747916e780bShannah_mairs PetscErrorCode PetscGaussLobattoLegendreElementAdvectionCreate(PetscInt n,PetscReal *nodes,PetscReal *weights,PetscReal ***AA) 2748916e780bShannah_mairs { 2749916e780bShannah_mairs PetscReal **D; 2750916e780bShannah_mairs PetscErrorCode ierr; 2751916e780bShannah_mairs const PetscReal *gllweights = weights; 2752916e780bShannah_mairs const PetscInt glln = n; 2753916e780bShannah_mairs PetscInt i,j; 2754916e780bShannah_mairs 2755916e780bShannah_mairs PetscFunctionBegin; 2756916e780bShannah_mairs ierr = PetscGaussLobattoLegendreElementGradientCreate(n,nodes,weights,&D,NULL);CHKERRQ(ierr); 2757916e780bShannah_mairs for (i=0; i<glln; i++) { 2758916e780bShannah_mairs for (j=0; j<glln; j++) { 2759916e780bShannah_mairs D[i][j] = gllweights[i]*D[i][j]; 2760916e780bShannah_mairs } 2761916e780bShannah_mairs } 2762916e780bShannah_mairs *AA = D; 2763916e780bShannah_mairs PetscFunctionReturn(0); 2764916e780bShannah_mairs } 2765916e780bShannah_mairs 2766916e780bShannah_mairs /*@C 2767916e780bShannah_mairs PetscGaussLobattoLegendreElementAdvectionDestroy - frees the advection stiffness for a single 1d GLL element 2768916e780bShannah_mairs 2769916e780bShannah_mairs Not Collective 2770916e780bShannah_mairs 2771d8d19677SJose E. Roman Input Parameters: 2772916e780bShannah_mairs + n - the number of GLL nodes 2773916e780bShannah_mairs . nodes - the GLL nodes 2774916e780bShannah_mairs . weights - the GLL weights 2775916e780bShannah_mairs - A - advection 2776916e780bShannah_mairs 2777916e780bShannah_mairs Level: beginner 2778916e780bShannah_mairs 2779916e780bShannah_mairs .seealso: PetscDTGaussLobattoLegendreQuadrature(), PetscGaussLobattoLegendreElementAdvectionCreate() 2780916e780bShannah_mairs 2781916e780bShannah_mairs @*/ 2782916e780bShannah_mairs PetscErrorCode PetscGaussLobattoLegendreElementAdvectionDestroy(PetscInt n,PetscReal *nodes,PetscReal *weights,PetscReal ***AA) 2783916e780bShannah_mairs { 2784916e780bShannah_mairs PetscErrorCode ierr; 2785916e780bShannah_mairs 2786916e780bShannah_mairs PetscFunctionBegin; 2787916e780bShannah_mairs ierr = PetscFree((*AA)[0]);CHKERRQ(ierr); 2788916e780bShannah_mairs ierr = PetscFree(*AA);CHKERRQ(ierr); 2789916e780bShannah_mairs *AA = NULL; 2790916e780bShannah_mairs PetscFunctionReturn(0); 2791916e780bShannah_mairs } 2792916e780bShannah_mairs 2793916e780bShannah_mairs PetscErrorCode PetscGaussLobattoLegendreElementMassCreate(PetscInt n,PetscReal *nodes,PetscReal *weights,PetscReal ***AA) 2794916e780bShannah_mairs { 2795916e780bShannah_mairs PetscReal **A; 2796916e780bShannah_mairs PetscErrorCode ierr; 2797916e780bShannah_mairs const PetscReal *gllweights = weights; 2798916e780bShannah_mairs const PetscInt glln = n; 2799916e780bShannah_mairs PetscInt i,j; 2800916e780bShannah_mairs 2801916e780bShannah_mairs PetscFunctionBegin; 2802916e780bShannah_mairs ierr = PetscMalloc1(glln,&A);CHKERRQ(ierr); 2803916e780bShannah_mairs ierr = PetscMalloc1(glln*glln,&A[0]);CHKERRQ(ierr); 2804916e780bShannah_mairs for (i=1; i<glln; i++) A[i] = A[i-1]+glln; 2805916e780bShannah_mairs if (glln==1) {A[0][0] = 0.;} 2806916e780bShannah_mairs for (i=0; i<glln; i++) { 2807916e780bShannah_mairs for (j=0; j<glln; j++) { 2808916e780bShannah_mairs A[i][j] = 0.; 2809916e780bShannah_mairs if (j==i) A[i][j] = gllweights[i]; 2810916e780bShannah_mairs } 2811916e780bShannah_mairs } 2812916e780bShannah_mairs *AA = A; 2813916e780bShannah_mairs PetscFunctionReturn(0); 2814916e780bShannah_mairs } 2815916e780bShannah_mairs 2816916e780bShannah_mairs PetscErrorCode PetscGaussLobattoLegendreElementMassDestroy(PetscInt n,PetscReal *nodes,PetscReal *weights,PetscReal ***AA) 2817916e780bShannah_mairs { 2818916e780bShannah_mairs PetscErrorCode ierr; 2819916e780bShannah_mairs 2820916e780bShannah_mairs PetscFunctionBegin; 2821916e780bShannah_mairs ierr = PetscFree((*AA)[0]);CHKERRQ(ierr); 2822916e780bShannah_mairs ierr = PetscFree(*AA);CHKERRQ(ierr); 2823916e780bShannah_mairs *AA = NULL; 2824916e780bShannah_mairs PetscFunctionReturn(0); 2825916e780bShannah_mairs } 2826d4afb720SToby Isaac 2827d4afb720SToby Isaac /*@ 2828d4afb720SToby Isaac PetscDTIndexToBary - convert an index into a barycentric coordinate. 2829d4afb720SToby Isaac 2830d4afb720SToby Isaac Input Parameters: 2831d4afb720SToby Isaac + len - the desired length of the barycentric tuple (usually 1 more than the dimension it represents, so a barycentric coordinate in a triangle has length 3) 2832d4afb720SToby Isaac . sum - the value that the sum of the barycentric coordinates (which will be non-negative integers) should sum to 2833d4afb720SToby Isaac - index - the index to convert: should be >= 0 and < Binomial(len - 1 + sum, sum) 2834d4afb720SToby Isaac 2835d4afb720SToby Isaac Output Parameter: 2836d4afb720SToby Isaac . coord - will be filled with the barycentric coordinate 2837d4afb720SToby Isaac 2838d4afb720SToby Isaac Level: beginner 2839d4afb720SToby Isaac 2840d4afb720SToby Isaac Note: the indices map to barycentric coordinates in lexicographic order, where the first index is the 2841d4afb720SToby Isaac least significant and the last index is the most significant. 2842d4afb720SToby Isaac 2843fbdc3dfeSToby Isaac .seealso: PetscDTBaryToIndex() 2844d4afb720SToby Isaac @*/ 2845d4afb720SToby Isaac PetscErrorCode PetscDTIndexToBary(PetscInt len, PetscInt sum, PetscInt index, PetscInt coord[]) 2846d4afb720SToby Isaac { 2847d4afb720SToby Isaac PetscInt c, d, s, total, subtotal, nexttotal; 2848d4afb720SToby Isaac 2849d4afb720SToby Isaac PetscFunctionBeginHot; 28502c71b3e2SJacob Faibussowitsch PetscCheckFalse(len < 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "length must be non-negative"); 28512c71b3e2SJacob Faibussowitsch PetscCheckFalse(index < 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "index must be non-negative"); 2852d4afb720SToby Isaac if (!len) { 2853d4afb720SToby Isaac if (!sum && !index) PetscFunctionReturn(0); 2854d4afb720SToby Isaac SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid index or sum for length 0 barycentric coordinate"); 2855d4afb720SToby Isaac } 2856d4afb720SToby Isaac for (c = 1, total = 1; c <= len; c++) { 2857d4afb720SToby Isaac /* total is the number of ways to have a tuple of length c with sum */ 2858d4afb720SToby Isaac if (index < total) break; 2859d4afb720SToby Isaac total = (total * (sum + c)) / c; 2860d4afb720SToby Isaac } 28612c71b3e2SJacob Faibussowitsch PetscCheckFalse(c > len,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "index out of range"); 2862d4afb720SToby Isaac for (d = c; d < len; d++) coord[d] = 0; 2863d4afb720SToby Isaac for (s = 0, subtotal = 1, nexttotal = 1; c > 0;) { 2864d4afb720SToby Isaac /* subtotal is the number of ways to have a tuple of length c with sum s */ 2865d4afb720SToby Isaac /* nexttotal is the number of ways to have a tuple of length c-1 with sum s */ 2866d4afb720SToby Isaac if ((index + subtotal) >= total) { 2867d4afb720SToby Isaac coord[--c] = sum - s; 2868d4afb720SToby Isaac index -= (total - subtotal); 2869d4afb720SToby Isaac sum = s; 2870d4afb720SToby Isaac total = nexttotal; 2871d4afb720SToby Isaac subtotal = 1; 2872d4afb720SToby Isaac nexttotal = 1; 2873d4afb720SToby Isaac s = 0; 2874d4afb720SToby Isaac } else { 2875d4afb720SToby Isaac subtotal = (subtotal * (c + s)) / (s + 1); 2876d4afb720SToby Isaac nexttotal = (nexttotal * (c - 1 + s)) / (s + 1); 2877d4afb720SToby Isaac s++; 2878d4afb720SToby Isaac } 2879d4afb720SToby Isaac } 2880d4afb720SToby Isaac PetscFunctionReturn(0); 2881d4afb720SToby Isaac } 2882d4afb720SToby Isaac 2883d4afb720SToby Isaac /*@ 2884d4afb720SToby Isaac PetscDTBaryToIndex - convert a barycentric coordinate to an index 2885d4afb720SToby Isaac 2886d4afb720SToby Isaac Input Parameters: 2887d4afb720SToby Isaac + len - the desired length of the barycentric tuple (usually 1 more than the dimension it represents, so a barycentric coordinate in a triangle has length 3) 2888d4afb720SToby Isaac . sum - the value that the sum of the barycentric coordinates (which will be non-negative integers) should sum to 2889d4afb720SToby Isaac - coord - a barycentric coordinate with the given length and sum 2890d4afb720SToby Isaac 2891d4afb720SToby Isaac Output Parameter: 2892d4afb720SToby Isaac . index - the unique index for the coordinate, >= 0 and < Binomial(len - 1 + sum, sum) 2893d4afb720SToby Isaac 2894d4afb720SToby Isaac Level: beginner 2895d4afb720SToby Isaac 2896d4afb720SToby Isaac Note: the indices map to barycentric coordinates in lexicographic order, where the first index is the 2897d4afb720SToby Isaac least significant and the last index is the most significant. 2898d4afb720SToby Isaac 2899d4afb720SToby Isaac .seealso: PetscDTIndexToBary 2900d4afb720SToby Isaac @*/ 2901d4afb720SToby Isaac PetscErrorCode PetscDTBaryToIndex(PetscInt len, PetscInt sum, const PetscInt coord[], PetscInt *index) 2902d4afb720SToby Isaac { 2903d4afb720SToby Isaac PetscInt c; 2904d4afb720SToby Isaac PetscInt i; 2905d4afb720SToby Isaac PetscInt total; 2906d4afb720SToby Isaac 2907d4afb720SToby Isaac PetscFunctionBeginHot; 29082c71b3e2SJacob Faibussowitsch PetscCheckFalse(len < 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "length must be non-negative"); 2909d4afb720SToby Isaac if (!len) { 2910d4afb720SToby Isaac if (!sum) { 2911d4afb720SToby Isaac *index = 0; 2912d4afb720SToby Isaac PetscFunctionReturn(0); 2913d4afb720SToby Isaac } 2914d4afb720SToby Isaac SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid index or sum for length 0 barycentric coordinate"); 2915d4afb720SToby Isaac } 2916d4afb720SToby Isaac for (c = 1, total = 1; c < len; c++) total = (total * (sum + c)) / c; 2917d4afb720SToby Isaac i = total - 1; 2918d4afb720SToby Isaac c = len - 1; 2919d4afb720SToby Isaac sum -= coord[c]; 2920d4afb720SToby Isaac while (sum > 0) { 2921d4afb720SToby Isaac PetscInt subtotal; 2922d4afb720SToby Isaac PetscInt s; 2923d4afb720SToby Isaac 2924d4afb720SToby Isaac for (s = 1, subtotal = 1; s < sum; s++) subtotal = (subtotal * (c + s)) / s; 2925d4afb720SToby Isaac i -= subtotal; 2926d4afb720SToby Isaac sum -= coord[--c]; 2927d4afb720SToby Isaac } 2928d4afb720SToby Isaac *index = i; 2929d4afb720SToby Isaac PetscFunctionReturn(0); 2930d4afb720SToby Isaac } 2931