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 15d3c69ad0SToby Isaac const char *const PetscDTNodeTypes_shifted[] = {"default", "gaussjacobi", "equispaced", "tanhsinh", "PETSCDTNODES_", NULL}; 16d3c69ad0SToby Isaac const char *const *const PetscDTNodeTypes = PetscDTNodeTypes_shifted + 1; 17d3c69ad0SToby Isaac 18d3c69ad0SToby Isaac const char *const PetscDTSimplexQuadratureTypes_shifted[] = {"default", "conic", "minsym", "PETSCDTSIMPLEXQUAD_", NULL}; 19d3c69ad0SToby Isaac const char *const *const PetscDTSimplexQuadratureTypes = PetscDTSimplexQuadratureTypes_shifted + 1; 20d4afb720SToby Isaac 21e6a796c3SToby Isaac static PetscBool GolubWelschCite = PETSC_FALSE; 22e6a796c3SToby Isaac const char GolubWelschCitation[] = "@article{GolubWelsch1969,\n" 230bfcf5a5SMatthew G. Knepley " author = {Golub and Welsch},\n" 240bfcf5a5SMatthew G. Knepley " title = {Calculation of Quadrature Rules},\n" 250bfcf5a5SMatthew G. Knepley " journal = {Math. Comp.},\n" 260bfcf5a5SMatthew G. Knepley " volume = {23},\n" 270bfcf5a5SMatthew G. Knepley " number = {106},\n" 280bfcf5a5SMatthew G. Knepley " pages = {221--230},\n" 290bfcf5a5SMatthew G. Knepley " year = {1969}\n}\n"; 300bfcf5a5SMatthew G. Knepley 31c4762a1bSJed Brown /* Numerical tests in src/dm/dt/tests/ex1.c show that when computing the nodes and weights of Gauss-Jacobi 3294e21283SToby Isaac quadrature rules: 33e6a796c3SToby Isaac 3494e21283SToby Isaac - in double precision, Newton's method and Golub & Welsch both work for moderate degrees (< 100), 3594e21283SToby Isaac - in single precision, Newton's method starts producing incorrect roots around n = 15, but 3694e21283SToby Isaac the weights from Golub & Welsch become a problem before then: they produces errors 3794e21283SToby Isaac in computing the Jacobi-polynomial Gram matrix around n = 6. 3894e21283SToby Isaac 3994e21283SToby Isaac So we default to Newton's method (required fewer dependencies) */ 4094e21283SToby Isaac PetscBool PetscDTGaussQuadratureNewton_Internal = PETSC_TRUE; 412cd22861SMatthew G. Knepley 422cd22861SMatthew G. Knepley PetscClassId PETSCQUADRATURE_CLASSID = 0; 432cd22861SMatthew G. Knepley 4440d8ff71SMatthew G. Knepley /*@ 4540d8ff71SMatthew G. Knepley PetscQuadratureCreate - Create a PetscQuadrature object 4640d8ff71SMatthew G. Knepley 47d083f849SBarry Smith Collective 4840d8ff71SMatthew G. Knepley 4940d8ff71SMatthew G. Knepley Input Parameter: 5040d8ff71SMatthew G. Knepley . comm - The communicator for the PetscQuadrature object 5140d8ff71SMatthew G. Knepley 5240d8ff71SMatthew G. Knepley Output Parameter: 5340d8ff71SMatthew G. Knepley . q - The PetscQuadrature object 5440d8ff71SMatthew G. Knepley 5540d8ff71SMatthew G. Knepley Level: beginner 5640d8ff71SMatthew G. Knepley 57db781477SPatrick Sanan .seealso: `PetscQuadratureDestroy()`, `PetscQuadratureGetData()` 5840d8ff71SMatthew G. Knepley @*/ 599371c9d4SSatish Balay PetscErrorCode PetscQuadratureCreate(MPI_Comm comm, PetscQuadrature *q) { 6021454ff5SMatthew G. Knepley PetscFunctionBegin; 6121454ff5SMatthew G. Knepley PetscValidPointer(q, 2); 629566063dSJacob Faibussowitsch PetscCall(DMInitializePackage()); 639566063dSJacob Faibussowitsch PetscCall(PetscHeaderCreate(*q, PETSCQUADRATURE_CLASSID, "PetscQuadrature", "Quadrature", "DT", comm, PetscQuadratureDestroy, PetscQuadratureView)); 6421454ff5SMatthew G. Knepley (*q)->dim = -1; 65a6b92713SMatthew G. Knepley (*q)->Nc = 1; 66bcede257SMatthew G. Knepley (*q)->order = -1; 6721454ff5SMatthew G. Knepley (*q)->numPoints = 0; 6821454ff5SMatthew G. Knepley (*q)->points = NULL; 6921454ff5SMatthew G. Knepley (*q)->weights = NULL; 7021454ff5SMatthew G. Knepley PetscFunctionReturn(0); 7121454ff5SMatthew G. Knepley } 7221454ff5SMatthew G. Knepley 73c9638911SMatthew G. Knepley /*@ 74c9638911SMatthew G. Knepley PetscQuadratureDuplicate - Create a deep copy of the PetscQuadrature object 75c9638911SMatthew G. Knepley 76d083f849SBarry Smith Collective on q 77c9638911SMatthew G. Knepley 78c9638911SMatthew G. Knepley Input Parameter: 79c9638911SMatthew G. Knepley . q - The PetscQuadrature object 80c9638911SMatthew G. Knepley 81c9638911SMatthew G. Knepley Output Parameter: 82c9638911SMatthew G. Knepley . r - The new PetscQuadrature object 83c9638911SMatthew G. Knepley 84c9638911SMatthew G. Knepley Level: beginner 85c9638911SMatthew G. Knepley 86db781477SPatrick Sanan .seealso: `PetscQuadratureCreate()`, `PetscQuadratureDestroy()`, `PetscQuadratureGetData()` 87c9638911SMatthew G. Knepley @*/ 889371c9d4SSatish Balay PetscErrorCode PetscQuadratureDuplicate(PetscQuadrature q, PetscQuadrature *r) { 89a6b92713SMatthew G. Knepley PetscInt order, dim, Nc, Nq; 90c9638911SMatthew G. Knepley const PetscReal *points, *weights; 91c9638911SMatthew G. Knepley PetscReal *p, *w; 92c9638911SMatthew G. Knepley 93c9638911SMatthew G. Knepley PetscFunctionBegin; 94064a246eSJacob Faibussowitsch PetscValidPointer(q, 1); 959566063dSJacob Faibussowitsch PetscCall(PetscQuadratureCreate(PetscObjectComm((PetscObject)q), r)); 969566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetOrder(q, &order)); 979566063dSJacob Faibussowitsch PetscCall(PetscQuadratureSetOrder(*r, order)); 989566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(q, &dim, &Nc, &Nq, &points, &weights)); 999566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(Nq * dim, &p)); 1009566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(Nq * Nc, &w)); 1019566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(p, points, Nq * dim)); 1029566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(w, weights, Nc * Nq)); 1039566063dSJacob Faibussowitsch PetscCall(PetscQuadratureSetData(*r, dim, Nc, Nq, p, w)); 104c9638911SMatthew G. Knepley PetscFunctionReturn(0); 105c9638911SMatthew G. Knepley } 106c9638911SMatthew G. Knepley 10740d8ff71SMatthew G. Knepley /*@ 10840d8ff71SMatthew G. Knepley PetscQuadratureDestroy - Destroys a PetscQuadrature object 10940d8ff71SMatthew G. Knepley 110d083f849SBarry Smith Collective on q 11140d8ff71SMatthew G. Knepley 11240d8ff71SMatthew G. Knepley Input Parameter: 11340d8ff71SMatthew G. Knepley . q - The PetscQuadrature object 11440d8ff71SMatthew G. Knepley 11540d8ff71SMatthew G. Knepley Level: beginner 11640d8ff71SMatthew G. Knepley 117db781477SPatrick Sanan .seealso: `PetscQuadratureCreate()`, `PetscQuadratureGetData()` 11840d8ff71SMatthew G. Knepley @*/ 1199371c9d4SSatish Balay PetscErrorCode PetscQuadratureDestroy(PetscQuadrature *q) { 120bfa639d9SMatthew G. Knepley PetscFunctionBegin; 12121454ff5SMatthew G. Knepley if (!*q) PetscFunctionReturn(0); 1222cd22861SMatthew G. Knepley PetscValidHeaderSpecific((*q), PETSCQUADRATURE_CLASSID, 1); 12321454ff5SMatthew G. Knepley if (--((PetscObject)(*q))->refct > 0) { 12421454ff5SMatthew G. Knepley *q = NULL; 12521454ff5SMatthew G. Knepley PetscFunctionReturn(0); 12621454ff5SMatthew G. Knepley } 1279566063dSJacob Faibussowitsch PetscCall(PetscFree((*q)->points)); 1289566063dSJacob Faibussowitsch PetscCall(PetscFree((*q)->weights)); 1299566063dSJacob Faibussowitsch PetscCall(PetscHeaderDestroy(q)); 13021454ff5SMatthew G. Knepley PetscFunctionReturn(0); 13121454ff5SMatthew G. Knepley } 13221454ff5SMatthew G. Knepley 133bcede257SMatthew G. Knepley /*@ 134a6b92713SMatthew G. Knepley PetscQuadratureGetOrder - Return the order of the method 135bcede257SMatthew G. Knepley 136bcede257SMatthew G. Knepley Not collective 137bcede257SMatthew G. Knepley 138bcede257SMatthew G. Knepley Input Parameter: 139bcede257SMatthew G. Knepley . q - The PetscQuadrature object 140bcede257SMatthew G. Knepley 141bcede257SMatthew G. Knepley Output Parameter: 142bcede257SMatthew G. Knepley . order - The order of the quadrature, i.e. the highest degree polynomial that is exactly integrated 143bcede257SMatthew G. Knepley 144bcede257SMatthew G. Knepley Level: intermediate 145bcede257SMatthew G. Knepley 146db781477SPatrick Sanan .seealso: `PetscQuadratureSetOrder()`, `PetscQuadratureGetData()`, `PetscQuadratureSetData()` 147bcede257SMatthew G. Knepley @*/ 1489371c9d4SSatish Balay PetscErrorCode PetscQuadratureGetOrder(PetscQuadrature q, PetscInt *order) { 149bcede257SMatthew G. Knepley PetscFunctionBegin; 1502cd22861SMatthew G. Knepley PetscValidHeaderSpecific(q, PETSCQUADRATURE_CLASSID, 1); 151dadcf809SJacob Faibussowitsch PetscValidIntPointer(order, 2); 152bcede257SMatthew G. Knepley *order = q->order; 153bcede257SMatthew G. Knepley PetscFunctionReturn(0); 154bcede257SMatthew G. Knepley } 155bcede257SMatthew G. Knepley 156bcede257SMatthew G. Knepley /*@ 157a6b92713SMatthew G. Knepley PetscQuadratureSetOrder - Return the order of the method 158bcede257SMatthew G. Knepley 159bcede257SMatthew G. Knepley Not collective 160bcede257SMatthew G. Knepley 161bcede257SMatthew G. Knepley Input Parameters: 162bcede257SMatthew G. Knepley + q - The PetscQuadrature object 163bcede257SMatthew G. Knepley - order - The order of the quadrature, i.e. the highest degree polynomial that is exactly integrated 164bcede257SMatthew G. Knepley 165bcede257SMatthew G. Knepley Level: intermediate 166bcede257SMatthew G. Knepley 167db781477SPatrick Sanan .seealso: `PetscQuadratureGetOrder()`, `PetscQuadratureGetData()`, `PetscQuadratureSetData()` 168bcede257SMatthew G. Knepley @*/ 1699371c9d4SSatish Balay PetscErrorCode PetscQuadratureSetOrder(PetscQuadrature q, PetscInt order) { 170bcede257SMatthew G. Knepley PetscFunctionBegin; 1712cd22861SMatthew G. Knepley PetscValidHeaderSpecific(q, PETSCQUADRATURE_CLASSID, 1); 172bcede257SMatthew G. Knepley q->order = order; 173bcede257SMatthew G. Knepley PetscFunctionReturn(0); 174bcede257SMatthew G. Knepley } 175bcede257SMatthew G. Knepley 176a6b92713SMatthew G. Knepley /*@ 177a6b92713SMatthew G. Knepley PetscQuadratureGetNumComponents - Return the number of components for functions to be integrated 178a6b92713SMatthew G. Knepley 179a6b92713SMatthew G. Knepley Not collective 180a6b92713SMatthew G. Knepley 181a6b92713SMatthew G. Knepley Input Parameter: 182a6b92713SMatthew G. Knepley . q - The PetscQuadrature object 183a6b92713SMatthew G. Knepley 184a6b92713SMatthew G. Knepley Output Parameter: 185a6b92713SMatthew G. Knepley . Nc - The number of components 186a6b92713SMatthew G. Knepley 187a6b92713SMatthew G. Knepley Note: We are performing an integral int f(x) . w(x) dx, where both f and w (the weight) have Nc components. 188a6b92713SMatthew G. Knepley 189a6b92713SMatthew G. Knepley Level: intermediate 190a6b92713SMatthew G. Knepley 191db781477SPatrick Sanan .seealso: `PetscQuadratureSetNumComponents()`, `PetscQuadratureGetData()`, `PetscQuadratureSetData()` 192a6b92713SMatthew G. Knepley @*/ 1939371c9d4SSatish Balay PetscErrorCode PetscQuadratureGetNumComponents(PetscQuadrature q, PetscInt *Nc) { 194a6b92713SMatthew G. Knepley PetscFunctionBegin; 1952cd22861SMatthew G. Knepley PetscValidHeaderSpecific(q, PETSCQUADRATURE_CLASSID, 1); 196dadcf809SJacob Faibussowitsch PetscValidIntPointer(Nc, 2); 197a6b92713SMatthew G. Knepley *Nc = q->Nc; 198a6b92713SMatthew G. Knepley PetscFunctionReturn(0); 199a6b92713SMatthew G. Knepley } 200a6b92713SMatthew G. Knepley 201a6b92713SMatthew G. Knepley /*@ 202a6b92713SMatthew G. Knepley PetscQuadratureSetNumComponents - Return the number of components for functions to be integrated 203a6b92713SMatthew G. Knepley 204a6b92713SMatthew G. Knepley Not collective 205a6b92713SMatthew G. Knepley 206a6b92713SMatthew G. Knepley Input Parameters: 207a6b92713SMatthew G. Knepley + q - The PetscQuadrature object 208a6b92713SMatthew G. Knepley - Nc - The number of components 209a6b92713SMatthew G. Knepley 210a6b92713SMatthew G. Knepley Note: We are performing an integral int f(x) . w(x) dx, where both f and w (the weight) have Nc components. 211a6b92713SMatthew G. Knepley 212a6b92713SMatthew G. Knepley Level: intermediate 213a6b92713SMatthew G. Knepley 214db781477SPatrick Sanan .seealso: `PetscQuadratureGetNumComponents()`, `PetscQuadratureGetData()`, `PetscQuadratureSetData()` 215a6b92713SMatthew G. Knepley @*/ 2169371c9d4SSatish Balay PetscErrorCode PetscQuadratureSetNumComponents(PetscQuadrature q, PetscInt Nc) { 217a6b92713SMatthew G. Knepley PetscFunctionBegin; 2182cd22861SMatthew G. Knepley PetscValidHeaderSpecific(q, PETSCQUADRATURE_CLASSID, 1); 219a6b92713SMatthew G. Knepley q->Nc = Nc; 220a6b92713SMatthew G. Knepley PetscFunctionReturn(0); 221a6b92713SMatthew G. Knepley } 222a6b92713SMatthew G. Knepley 22340d8ff71SMatthew G. Knepley /*@C 22440d8ff71SMatthew G. Knepley PetscQuadratureGetData - Returns the data defining the quadrature 22540d8ff71SMatthew G. Knepley 22640d8ff71SMatthew G. Knepley Not collective 22740d8ff71SMatthew G. Knepley 22840d8ff71SMatthew G. Knepley Input Parameter: 22940d8ff71SMatthew G. Knepley . q - The PetscQuadrature object 23040d8ff71SMatthew G. Knepley 23140d8ff71SMatthew G. Knepley Output Parameters: 23240d8ff71SMatthew G. Knepley + dim - The spatial dimension 233805e7170SToby Isaac . Nc - The number of components 23440d8ff71SMatthew G. Knepley . npoints - The number of quadrature points 23540d8ff71SMatthew G. Knepley . points - The coordinates of each quadrature point 23640d8ff71SMatthew G. Knepley - weights - The weight of each quadrature point 23740d8ff71SMatthew G. Knepley 23840d8ff71SMatthew G. Knepley Level: intermediate 23940d8ff71SMatthew G. Knepley 24095452b02SPatrick Sanan Fortran Notes: 24195452b02SPatrick Sanan From Fortran you must call PetscQuadratureRestoreData() when you are done with the data 2421fd49c25SBarry Smith 243db781477SPatrick Sanan .seealso: `PetscQuadratureCreate()`, `PetscQuadratureSetData()` 24440d8ff71SMatthew G. Knepley @*/ 2459371c9d4SSatish Balay PetscErrorCode PetscQuadratureGetData(PetscQuadrature q, PetscInt *dim, PetscInt *Nc, PetscInt *npoints, const PetscReal *points[], const PetscReal *weights[]) { 24621454ff5SMatthew G. Knepley PetscFunctionBegin; 2472cd22861SMatthew G. Knepley PetscValidHeaderSpecific(q, PETSCQUADRATURE_CLASSID, 1); 24821454ff5SMatthew G. Knepley if (dim) { 249dadcf809SJacob Faibussowitsch PetscValidIntPointer(dim, 2); 25021454ff5SMatthew G. Knepley *dim = q->dim; 25121454ff5SMatthew G. Knepley } 252a6b92713SMatthew G. Knepley if (Nc) { 253dadcf809SJacob Faibussowitsch PetscValidIntPointer(Nc, 3); 254a6b92713SMatthew G. Knepley *Nc = q->Nc; 255a6b92713SMatthew G. Knepley } 25621454ff5SMatthew G. Knepley if (npoints) { 257dadcf809SJacob Faibussowitsch PetscValidIntPointer(npoints, 4); 25821454ff5SMatthew G. Knepley *npoints = q->numPoints; 25921454ff5SMatthew G. Knepley } 26021454ff5SMatthew G. Knepley if (points) { 261a6b92713SMatthew G. Knepley PetscValidPointer(points, 5); 26221454ff5SMatthew G. Knepley *points = q->points; 26321454ff5SMatthew G. Knepley } 26421454ff5SMatthew G. Knepley if (weights) { 265a6b92713SMatthew G. Knepley PetscValidPointer(weights, 6); 26621454ff5SMatthew G. Knepley *weights = q->weights; 26721454ff5SMatthew G. Knepley } 26821454ff5SMatthew G. Knepley PetscFunctionReturn(0); 26921454ff5SMatthew G. Knepley } 27021454ff5SMatthew G. Knepley 2714f9ab2b4SJed Brown /*@ 2724f9ab2b4SJed Brown PetscQuadratureEqual - determine whether two quadratures are equivalent 2734f9ab2b4SJed Brown 2744f9ab2b4SJed Brown Input Parameters: 2754f9ab2b4SJed Brown + A - A PetscQuadrature object 2764f9ab2b4SJed Brown - B - Another PetscQuadrature object 2774f9ab2b4SJed Brown 2784f9ab2b4SJed Brown Output Parameters: 2794f9ab2b4SJed Brown . equal - PETSC_TRUE if the quadratures are the same 2804f9ab2b4SJed Brown 2814f9ab2b4SJed Brown Level: intermediate 2824f9ab2b4SJed Brown 283db781477SPatrick Sanan .seealso: `PetscQuadratureCreate()` 2844f9ab2b4SJed Brown @*/ 2859371c9d4SSatish Balay PetscErrorCode PetscQuadratureEqual(PetscQuadrature A, PetscQuadrature B, PetscBool *equal) { 2864f9ab2b4SJed Brown PetscFunctionBegin; 2874f9ab2b4SJed Brown PetscValidHeaderSpecific(A, PETSCQUADRATURE_CLASSID, 1); 2884f9ab2b4SJed Brown PetscValidHeaderSpecific(B, PETSCQUADRATURE_CLASSID, 2); 2894f9ab2b4SJed Brown PetscValidBoolPointer(equal, 3); 2904f9ab2b4SJed Brown *equal = PETSC_FALSE; 2919371c9d4SSatish Balay if (A->dim != B->dim || A->Nc != B->Nc || A->order != B->order || A->numPoints != B->numPoints) { PetscFunctionReturn(0); } 2924f9ab2b4SJed Brown for (PetscInt i = 0; i < A->numPoints * A->dim; i++) { 2939371c9d4SSatish Balay if (PetscAbsReal(A->points[i] - B->points[i]) > PETSC_SMALL) { PetscFunctionReturn(0); } 2944f9ab2b4SJed Brown } 2954f9ab2b4SJed Brown if (!A->weights && !B->weights) { 2964f9ab2b4SJed Brown *equal = PETSC_TRUE; 2974f9ab2b4SJed Brown PetscFunctionReturn(0); 2984f9ab2b4SJed Brown } 2994f9ab2b4SJed Brown if (A->weights && B->weights) { 3004f9ab2b4SJed Brown for (PetscInt i = 0; i < A->numPoints; i++) { 3019371c9d4SSatish Balay if (PetscAbsReal(A->weights[i] - B->weights[i]) > PETSC_SMALL) { PetscFunctionReturn(0); } 3024f9ab2b4SJed Brown } 3034f9ab2b4SJed Brown *equal = PETSC_TRUE; 3044f9ab2b4SJed Brown } 3054f9ab2b4SJed Brown PetscFunctionReturn(0); 3064f9ab2b4SJed Brown } 3074f9ab2b4SJed Brown 3089371c9d4SSatish Balay static PetscErrorCode PetscDTJacobianInverse_Internal(PetscInt m, PetscInt n, const PetscReal J[], PetscReal Jinv[]) { 309907761f8SToby Isaac PetscScalar *Js, *Jinvs; 310907761f8SToby Isaac PetscInt i, j, k; 311907761f8SToby Isaac PetscBLASInt bm, bn, info; 312907761f8SToby Isaac 313907761f8SToby Isaac PetscFunctionBegin; 314d4afb720SToby Isaac if (!m || !n) PetscFunctionReturn(0); 3159566063dSJacob Faibussowitsch PetscCall(PetscBLASIntCast(m, &bm)); 3169566063dSJacob Faibussowitsch PetscCall(PetscBLASIntCast(n, &bn)); 317907761f8SToby Isaac #if defined(PETSC_USE_COMPLEX) 3189566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(m * n, &Js, m * n, &Jinvs)); 31928222859SToby Isaac for (i = 0; i < m * n; i++) Js[i] = J[i]; 320907761f8SToby Isaac #else 321907761f8SToby Isaac Js = (PetscReal *)J; 322907761f8SToby Isaac Jinvs = Jinv; 323907761f8SToby Isaac #endif 324907761f8SToby Isaac if (m == n) { 325907761f8SToby Isaac PetscBLASInt *pivots; 326907761f8SToby Isaac PetscScalar *W; 327907761f8SToby Isaac 3289566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(m, &pivots, m, &W)); 329907761f8SToby Isaac 3309566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(Jinvs, Js, m * m)); 331792fecdfSBarry Smith PetscCallBLAS("LAPACKgetrf", LAPACKgetrf_(&bm, &bm, Jinvs, &bm, pivots, &info)); 33263a3b9bcSJacob Faibussowitsch PetscCheck(!info, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error returned from LAPACKgetrf %" PetscInt_FMT, (PetscInt)info); 333792fecdfSBarry Smith PetscCallBLAS("LAPACKgetri", LAPACKgetri_(&bm, Jinvs, &bm, pivots, W, &bm, &info)); 33463a3b9bcSJacob Faibussowitsch PetscCheck(!info, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error returned from LAPACKgetri %" PetscInt_FMT, (PetscInt)info); 3359566063dSJacob Faibussowitsch PetscCall(PetscFree2(pivots, W)); 336907761f8SToby Isaac } else if (m < n) { 337907761f8SToby Isaac PetscScalar *JJT; 338907761f8SToby Isaac PetscBLASInt *pivots; 339907761f8SToby Isaac PetscScalar *W; 340907761f8SToby Isaac 3419566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(m * m, &JJT)); 3429566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(m, &pivots, m, &W)); 343907761f8SToby Isaac for (i = 0; i < m; i++) { 344907761f8SToby Isaac for (j = 0; j < m; j++) { 345907761f8SToby Isaac PetscScalar val = 0.; 346907761f8SToby Isaac 347907761f8SToby Isaac for (k = 0; k < n; k++) val += Js[i * n + k] * Js[j * n + k]; 348907761f8SToby Isaac JJT[i * m + j] = val; 349907761f8SToby Isaac } 350907761f8SToby Isaac } 351907761f8SToby Isaac 352792fecdfSBarry Smith PetscCallBLAS("LAPACKgetrf", LAPACKgetrf_(&bm, &bm, JJT, &bm, pivots, &info)); 35363a3b9bcSJacob Faibussowitsch PetscCheck(!info, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error returned from LAPACKgetrf %" PetscInt_FMT, (PetscInt)info); 354792fecdfSBarry Smith PetscCallBLAS("LAPACKgetri", LAPACKgetri_(&bm, JJT, &bm, pivots, W, &bm, &info)); 35563a3b9bcSJacob Faibussowitsch PetscCheck(!info, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error returned from LAPACKgetri %" PetscInt_FMT, (PetscInt)info); 356907761f8SToby Isaac for (i = 0; i < n; i++) { 357907761f8SToby Isaac for (j = 0; j < m; j++) { 358907761f8SToby Isaac PetscScalar val = 0.; 359907761f8SToby Isaac 360907761f8SToby Isaac for (k = 0; k < m; k++) val += Js[k * n + i] * JJT[k * m + j]; 361907761f8SToby Isaac Jinvs[i * m + j] = val; 362907761f8SToby Isaac } 363907761f8SToby Isaac } 3649566063dSJacob Faibussowitsch PetscCall(PetscFree2(pivots, W)); 3659566063dSJacob Faibussowitsch PetscCall(PetscFree(JJT)); 366907761f8SToby Isaac } else { 367907761f8SToby Isaac PetscScalar *JTJ; 368907761f8SToby Isaac PetscBLASInt *pivots; 369907761f8SToby Isaac PetscScalar *W; 370907761f8SToby Isaac 3719566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(n * n, &JTJ)); 3729566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(n, &pivots, n, &W)); 373907761f8SToby Isaac for (i = 0; i < n; i++) { 374907761f8SToby Isaac for (j = 0; j < n; j++) { 375907761f8SToby Isaac PetscScalar val = 0.; 376907761f8SToby Isaac 377907761f8SToby Isaac for (k = 0; k < m; k++) val += Js[k * n + i] * Js[k * n + j]; 378907761f8SToby Isaac JTJ[i * n + j] = val; 379907761f8SToby Isaac } 380907761f8SToby Isaac } 381907761f8SToby Isaac 382792fecdfSBarry Smith PetscCallBLAS("LAPACKgetrf", LAPACKgetrf_(&bn, &bn, JTJ, &bn, pivots, &info)); 38363a3b9bcSJacob Faibussowitsch PetscCheck(!info, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error returned from LAPACKgetrf %" PetscInt_FMT, (PetscInt)info); 384792fecdfSBarry Smith PetscCallBLAS("LAPACKgetri", LAPACKgetri_(&bn, JTJ, &bn, pivots, W, &bn, &info)); 38563a3b9bcSJacob Faibussowitsch PetscCheck(!info, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error returned from LAPACKgetri %" PetscInt_FMT, (PetscInt)info); 386907761f8SToby Isaac for (i = 0; i < n; i++) { 387907761f8SToby Isaac for (j = 0; j < m; j++) { 388907761f8SToby Isaac PetscScalar val = 0.; 389907761f8SToby Isaac 390907761f8SToby Isaac for (k = 0; k < n; k++) val += JTJ[i * n + k] * Js[j * n + k]; 391907761f8SToby Isaac Jinvs[i * m + j] = val; 392907761f8SToby Isaac } 393907761f8SToby Isaac } 3949566063dSJacob Faibussowitsch PetscCall(PetscFree2(pivots, W)); 3959566063dSJacob Faibussowitsch PetscCall(PetscFree(JTJ)); 396907761f8SToby Isaac } 397907761f8SToby Isaac #if defined(PETSC_USE_COMPLEX) 39828222859SToby Isaac for (i = 0; i < m * n; i++) Jinv[i] = PetscRealPart(Jinvs[i]); 3999566063dSJacob Faibussowitsch PetscCall(PetscFree2(Js, Jinvs)); 400907761f8SToby Isaac #endif 401907761f8SToby Isaac PetscFunctionReturn(0); 402907761f8SToby Isaac } 403907761f8SToby Isaac 404907761f8SToby Isaac /*@ 405907761f8SToby Isaac PetscQuadraturePushForward - Push forward a quadrature functional under an affine transformation. 406907761f8SToby Isaac 407907761f8SToby Isaac Collecive on PetscQuadrature 408907761f8SToby Isaac 4094165533cSJose E. Roman Input Parameters: 410907761f8SToby Isaac + q - the quadrature functional 411907761f8SToby Isaac . imageDim - the dimension of the image of the transformation 412907761f8SToby Isaac . origin - a point in the original space 413907761f8SToby Isaac . originImage - the image of the origin under the transformation 414907761f8SToby Isaac . J - the Jacobian of the image: an [imageDim x dim] matrix in row major order 41528222859SToby 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] 416907761f8SToby Isaac 4174165533cSJose E. Roman Output Parameters: 418907761f8SToby 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. 419907761f8SToby Isaac 420907761f8SToby 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. 421907761f8SToby Isaac 4226c877ef6SSatish Balay Level: intermediate 4236c877ef6SSatish Balay 424db781477SPatrick Sanan .seealso: `PetscDTAltVPullback()`, `PetscDTAltVPullbackMatrix()` 425907761f8SToby Isaac @*/ 4269371c9d4SSatish Balay PetscErrorCode PetscQuadraturePushForward(PetscQuadrature q, PetscInt imageDim, const PetscReal origin[], const PetscReal originImage[], const PetscReal J[], PetscInt formDegree, PetscQuadrature *Jinvstarq) { 427907761f8SToby Isaac PetscInt dim, Nc, imageNc, formSize, Ncopies, imageFormSize, Npoints, pt, i, j, c; 428907761f8SToby Isaac const PetscReal *points; 429907761f8SToby Isaac const PetscReal *weights; 430907761f8SToby Isaac PetscReal *imagePoints, *imageWeights; 431907761f8SToby Isaac PetscReal *Jinv; 432907761f8SToby Isaac PetscReal *Jinvstar; 433907761f8SToby Isaac 434907761f8SToby Isaac PetscFunctionBegin; 435d4afb720SToby Isaac PetscValidHeaderSpecific(q, PETSCQUADRATURE_CLASSID, 1); 43663a3b9bcSJacob Faibussowitsch PetscCheck(imageDim >= PetscAbsInt(formDegree), PetscObjectComm((PetscObject)q), PETSC_ERR_ARG_INCOMP, "Cannot represent a %" PetscInt_FMT "-form in %" PetscInt_FMT " dimensions", PetscAbsInt(formDegree), imageDim); 4379566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(q, &dim, &Nc, &Npoints, &points, &weights)); 4389566063dSJacob Faibussowitsch PetscCall(PetscDTBinomialInt(dim, PetscAbsInt(formDegree), &formSize)); 43963a3b9bcSJacob Faibussowitsch PetscCheck(Nc % formSize == 0, PetscObjectComm((PetscObject)q), PETSC_ERR_ARG_INCOMP, "Number of components %" PetscInt_FMT " is not a multiple of formSize %" PetscInt_FMT, Nc, formSize); 440907761f8SToby Isaac Ncopies = Nc / formSize; 4419566063dSJacob Faibussowitsch PetscCall(PetscDTBinomialInt(imageDim, PetscAbsInt(formDegree), &imageFormSize)); 442907761f8SToby Isaac imageNc = Ncopies * imageFormSize; 4439566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(Npoints * imageDim, &imagePoints)); 4449566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(Npoints * imageNc, &imageWeights)); 4459566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(imageDim * dim, &Jinv, formSize * imageFormSize, &Jinvstar)); 4469566063dSJacob Faibussowitsch PetscCall(PetscDTJacobianInverse_Internal(imageDim, dim, J, Jinv)); 4479566063dSJacob Faibussowitsch PetscCall(PetscDTAltVPullbackMatrix(imageDim, dim, Jinv, formDegree, Jinvstar)); 448907761f8SToby Isaac for (pt = 0; pt < Npoints; pt++) { 449907761f8SToby Isaac const PetscReal *point = &points[pt * dim]; 450907761f8SToby Isaac PetscReal *imagePoint = &imagePoints[pt * imageDim]; 451907761f8SToby Isaac 452907761f8SToby Isaac for (i = 0; i < imageDim; i++) { 453907761f8SToby Isaac PetscReal val = originImage[i]; 454907761f8SToby Isaac 455907761f8SToby Isaac for (j = 0; j < dim; j++) val += J[i * dim + j] * (point[j] - origin[j]); 456907761f8SToby Isaac imagePoint[i] = val; 457907761f8SToby Isaac } 458907761f8SToby Isaac for (c = 0; c < Ncopies; c++) { 459907761f8SToby Isaac const PetscReal *form = &weights[pt * Nc + c * formSize]; 460907761f8SToby Isaac PetscReal *imageForm = &imageWeights[pt * imageNc + c * imageFormSize]; 461907761f8SToby Isaac 462907761f8SToby Isaac for (i = 0; i < imageFormSize; i++) { 463907761f8SToby Isaac PetscReal val = 0.; 464907761f8SToby Isaac 465907761f8SToby Isaac for (j = 0; j < formSize; j++) val += Jinvstar[i * formSize + j] * form[j]; 466907761f8SToby Isaac imageForm[i] = val; 467907761f8SToby Isaac } 468907761f8SToby Isaac } 469907761f8SToby Isaac } 4709566063dSJacob Faibussowitsch PetscCall(PetscQuadratureCreate(PetscObjectComm((PetscObject)q), Jinvstarq)); 4719566063dSJacob Faibussowitsch PetscCall(PetscQuadratureSetData(*Jinvstarq, imageDim, imageNc, Npoints, imagePoints, imageWeights)); 4729566063dSJacob Faibussowitsch PetscCall(PetscFree2(Jinv, Jinvstar)); 473907761f8SToby Isaac PetscFunctionReturn(0); 474907761f8SToby Isaac } 475907761f8SToby Isaac 47640d8ff71SMatthew G. Knepley /*@C 47740d8ff71SMatthew G. Knepley PetscQuadratureSetData - Sets the data defining the quadrature 47840d8ff71SMatthew G. Knepley 47940d8ff71SMatthew G. Knepley Not collective 48040d8ff71SMatthew G. Knepley 48140d8ff71SMatthew G. Knepley Input Parameters: 48240d8ff71SMatthew G. Knepley + q - The PetscQuadrature object 48340d8ff71SMatthew G. Knepley . dim - The spatial dimension 484e2b35d93SBarry Smith . Nc - The number of components 48540d8ff71SMatthew G. Knepley . npoints - The number of quadrature points 48640d8ff71SMatthew G. Knepley . points - The coordinates of each quadrature point 48740d8ff71SMatthew G. Knepley - weights - The weight of each quadrature point 48840d8ff71SMatthew G. Knepley 489c99e0549SMatthew 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. 490f2fd9e53SMatthew G. Knepley 49140d8ff71SMatthew G. Knepley Level: intermediate 49240d8ff71SMatthew G. Knepley 493db781477SPatrick Sanan .seealso: `PetscQuadratureCreate()`, `PetscQuadratureGetData()` 49440d8ff71SMatthew G. Knepley @*/ 4959371c9d4SSatish Balay PetscErrorCode PetscQuadratureSetData(PetscQuadrature q, PetscInt dim, PetscInt Nc, PetscInt npoints, const PetscReal points[], const PetscReal weights[]) { 49621454ff5SMatthew G. Knepley PetscFunctionBegin; 4972cd22861SMatthew G. Knepley PetscValidHeaderSpecific(q, PETSCQUADRATURE_CLASSID, 1); 49821454ff5SMatthew G. Knepley if (dim >= 0) q->dim = dim; 499a6b92713SMatthew G. Knepley if (Nc >= 0) q->Nc = Nc; 50021454ff5SMatthew G. Knepley if (npoints >= 0) q->numPoints = npoints; 50121454ff5SMatthew G. Knepley if (points) { 502dadcf809SJacob Faibussowitsch PetscValidRealPointer(points, 5); 50321454ff5SMatthew G. Knepley q->points = points; 50421454ff5SMatthew G. Knepley } 50521454ff5SMatthew G. Knepley if (weights) { 506dadcf809SJacob Faibussowitsch PetscValidRealPointer(weights, 6); 50721454ff5SMatthew G. Knepley q->weights = weights; 50821454ff5SMatthew G. Knepley } 509f9fd7fdbSMatthew G. Knepley PetscFunctionReturn(0); 510f9fd7fdbSMatthew G. Knepley } 511f9fd7fdbSMatthew G. Knepley 5129371c9d4SSatish Balay static PetscErrorCode PetscQuadratureView_Ascii(PetscQuadrature quad, PetscViewer v) { 513d9bac1caSLisandro Dalcin PetscInt q, d, c; 514d9bac1caSLisandro Dalcin PetscViewerFormat format; 515d9bac1caSLisandro Dalcin 516d9bac1caSLisandro Dalcin PetscFunctionBegin; 51763a3b9bcSJacob Faibussowitsch if (quad->Nc > 1) PetscCall(PetscViewerASCIIPrintf(v, "Quadrature of order %" PetscInt_FMT " on %" PetscInt_FMT " points (dim %" PetscInt_FMT ") with %" PetscInt_FMT " components\n", quad->order, quad->numPoints, quad->dim, quad->Nc)); 51863a3b9bcSJacob Faibussowitsch else PetscCall(PetscViewerASCIIPrintf(v, "Quadrature of order %" PetscInt_FMT " on %" PetscInt_FMT " points (dim %" PetscInt_FMT ")\n", quad->order, quad->numPoints, quad->dim)); 5199566063dSJacob Faibussowitsch PetscCall(PetscViewerGetFormat(v, &format)); 520d9bac1caSLisandro Dalcin if (format != PETSC_VIEWER_ASCII_INFO_DETAIL) PetscFunctionReturn(0); 521d9bac1caSLisandro Dalcin for (q = 0; q < quad->numPoints; ++q) { 52263a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(v, "p%" PetscInt_FMT " (", q)); 5239566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIUseTabs(v, PETSC_FALSE)); 524d9bac1caSLisandro Dalcin for (d = 0; d < quad->dim; ++d) { 5259566063dSJacob Faibussowitsch if (d) PetscCall(PetscViewerASCIIPrintf(v, ", ")); 5269566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(v, "%+g", (double)quad->points[q * quad->dim + d])); 527d9bac1caSLisandro Dalcin } 5289566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(v, ") ")); 52963a3b9bcSJacob Faibussowitsch if (quad->Nc > 1) PetscCall(PetscViewerASCIIPrintf(v, "w%" PetscInt_FMT " (", q)); 530d9bac1caSLisandro Dalcin for (c = 0; c < quad->Nc; ++c) { 5319566063dSJacob Faibussowitsch if (c) PetscCall(PetscViewerASCIIPrintf(v, ", ")); 5329566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(v, "%+g", (double)quad->weights[q * quad->Nc + c])); 533d9bac1caSLisandro Dalcin } 5349566063dSJacob Faibussowitsch if (quad->Nc > 1) PetscCall(PetscViewerASCIIPrintf(v, ")")); 5359566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(v, "\n")); 5369566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIUseTabs(v, PETSC_TRUE)); 537d9bac1caSLisandro Dalcin } 538d9bac1caSLisandro Dalcin PetscFunctionReturn(0); 539d9bac1caSLisandro Dalcin } 540d9bac1caSLisandro Dalcin 54140d8ff71SMatthew G. Knepley /*@C 54240d8ff71SMatthew G. Knepley PetscQuadratureView - Views a PetscQuadrature object 54340d8ff71SMatthew G. Knepley 544d083f849SBarry Smith Collective on quad 54540d8ff71SMatthew G. Knepley 54640d8ff71SMatthew G. Knepley Input Parameters: 547d9bac1caSLisandro Dalcin + quad - The PetscQuadrature object 54840d8ff71SMatthew G. Knepley - viewer - The PetscViewer object 54940d8ff71SMatthew G. Knepley 55040d8ff71SMatthew G. Knepley Level: beginner 55140d8ff71SMatthew G. Knepley 552db781477SPatrick Sanan .seealso: `PetscQuadratureCreate()`, `PetscQuadratureGetData()` 55340d8ff71SMatthew G. Knepley @*/ 5549371c9d4SSatish Balay PetscErrorCode PetscQuadratureView(PetscQuadrature quad, PetscViewer viewer) { 555d9bac1caSLisandro Dalcin PetscBool iascii; 556f9fd7fdbSMatthew G. Knepley 557f9fd7fdbSMatthew G. Knepley PetscFunctionBegin; 558d9bac1caSLisandro Dalcin PetscValidHeader(quad, 1); 559d9bac1caSLisandro Dalcin if (viewer) PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 5609566063dSJacob Faibussowitsch if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)quad), &viewer)); 5619566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 5629566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(viewer)); 5639566063dSJacob Faibussowitsch if (iascii) PetscCall(PetscQuadratureView_Ascii(quad, viewer)); 5649566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(viewer)); 565bfa639d9SMatthew G. Knepley PetscFunctionReturn(0); 566bfa639d9SMatthew G. Knepley } 567bfa639d9SMatthew G. Knepley 56889710940SMatthew G. Knepley /*@C 56989710940SMatthew G. Knepley PetscQuadratureExpandComposite - Return a quadrature over the composite element, which has the original quadrature in each subelement 57089710940SMatthew G. Knepley 57189710940SMatthew G. Knepley Not collective 57289710940SMatthew G. Knepley 573d8d19677SJose E. Roman Input Parameters: 57489710940SMatthew G. Knepley + q - The original PetscQuadrature 57589710940SMatthew G. Knepley . numSubelements - The number of subelements the original element is divided into 57689710940SMatthew G. Knepley . v0 - An array of the initial points for each subelement 57789710940SMatthew G. Knepley - jac - An array of the Jacobian mappings from the reference to each subelement 57889710940SMatthew G. Knepley 57989710940SMatthew G. Knepley Output Parameters: 58089710940SMatthew G. Knepley . dim - The dimension 58189710940SMatthew G. Knepley 58289710940SMatthew G. Knepley Note: Together v0 and jac define an affine mapping from the original reference element to each subelement 58389710940SMatthew G. Knepley 584f5f57ec0SBarry Smith Not available from Fortran 585f5f57ec0SBarry Smith 58689710940SMatthew G. Knepley Level: intermediate 58789710940SMatthew G. Knepley 588db781477SPatrick Sanan .seealso: `PetscFECreate()`, `PetscSpaceGetDimension()`, `PetscDualSpaceGetDimension()` 58989710940SMatthew G. Knepley @*/ 5909371c9d4SSatish Balay PetscErrorCode PetscQuadratureExpandComposite(PetscQuadrature q, PetscInt numSubelements, const PetscReal v0[], const PetscReal jac[], PetscQuadrature *qref) { 59189710940SMatthew G. Knepley const PetscReal *points, *weights; 59289710940SMatthew G. Knepley PetscReal *pointsRef, *weightsRef; 593a6b92713SMatthew G. Knepley PetscInt dim, Nc, order, npoints, npointsRef, c, p, cp, d, e; 59489710940SMatthew G. Knepley 59589710940SMatthew G. Knepley PetscFunctionBegin; 5962cd22861SMatthew G. Knepley PetscValidHeaderSpecific(q, PETSCQUADRATURE_CLASSID, 1); 597dadcf809SJacob Faibussowitsch PetscValidRealPointer(v0, 3); 598dadcf809SJacob Faibussowitsch PetscValidRealPointer(jac, 4); 59989710940SMatthew G. Knepley PetscValidPointer(qref, 5); 6009566063dSJacob Faibussowitsch PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, qref)); 6019566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetOrder(q, &order)); 6029566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(q, &dim, &Nc, &npoints, &points, &weights)); 60389710940SMatthew G. Knepley npointsRef = npoints * numSubelements; 6049566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(npointsRef * dim, &pointsRef)); 6059566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(npointsRef * Nc, &weightsRef)); 60689710940SMatthew G. Knepley for (c = 0; c < numSubelements; ++c) { 60789710940SMatthew G. Knepley for (p = 0; p < npoints; ++p) { 60889710940SMatthew G. Knepley for (d = 0; d < dim; ++d) { 60989710940SMatthew G. Knepley pointsRef[(c * npoints + p) * dim + d] = v0[c * dim + d]; 6109371c9d4SSatish Balay for (e = 0; e < dim; ++e) { pointsRef[(c * npoints + p) * dim + d] += jac[(c * dim + d) * dim + e] * (points[p * dim + e] + 1.0); } 61189710940SMatthew G. Knepley } 61289710940SMatthew G. Knepley /* Could also use detJ here */ 613a6b92713SMatthew G. Knepley for (cp = 0; cp < Nc; ++cp) weightsRef[(c * npoints + p) * Nc + cp] = weights[p * Nc + cp] / numSubelements; 61489710940SMatthew G. Knepley } 61589710940SMatthew G. Knepley } 6169566063dSJacob Faibussowitsch PetscCall(PetscQuadratureSetOrder(*qref, order)); 6179566063dSJacob Faibussowitsch PetscCall(PetscQuadratureSetData(*qref, dim, Nc, npointsRef, pointsRef, weightsRef)); 61889710940SMatthew G. Knepley PetscFunctionReturn(0); 61989710940SMatthew G. Knepley } 62089710940SMatthew G. Knepley 62194e21283SToby Isaac /* Compute the coefficients for the Jacobi polynomial recurrence, 62294e21283SToby Isaac * 62394e21283SToby Isaac * J^{a,b}_n(x) = (cnm1 + cnm1x * x) * J^{a,b}_{n-1}(x) - cnm2 * J^{a,b}_{n-2}(x). 62494e21283SToby Isaac */ 62594e21283SToby Isaac #define PetscDTJacobiRecurrence_Internal(n, a, b, cnm1, cnm1x, cnm2) \ 62694e21283SToby Isaac do { \ 62794e21283SToby Isaac PetscReal _a = (a); \ 62894e21283SToby Isaac PetscReal _b = (b); \ 62994e21283SToby Isaac PetscReal _n = (n); \ 63094e21283SToby Isaac if (n == 1) { \ 63194e21283SToby Isaac (cnm1) = (_a - _b) * 0.5; \ 63294e21283SToby Isaac (cnm1x) = (_a + _b + 2.) * 0.5; \ 63394e21283SToby Isaac (cnm2) = 0.; \ 63494e21283SToby Isaac } else { \ 63594e21283SToby Isaac PetscReal _2n = _n + _n; \ 63694e21283SToby Isaac PetscReal _d = (_2n * (_n + _a + _b) * (_2n + _a + _b - 2)); \ 63794e21283SToby Isaac PetscReal _n1 = (_2n + _a + _b - 1.) * (_a * _a - _b * _b); \ 63894e21283SToby Isaac PetscReal _n1x = (_2n + _a + _b - 1.) * (_2n + _a + _b) * (_2n + _a + _b - 2); \ 63994e21283SToby Isaac PetscReal _n2 = 2. * ((_n + _a - 1.) * (_n + _b - 1.) * (_2n + _a + _b)); \ 64094e21283SToby Isaac (cnm1) = _n1 / _d; \ 64194e21283SToby Isaac (cnm1x) = _n1x / _d; \ 64294e21283SToby Isaac (cnm2) = _n2 / _d; \ 64394e21283SToby Isaac } \ 64494e21283SToby Isaac } while (0) 64594e21283SToby Isaac 646fbdc3dfeSToby Isaac /*@ 647fbdc3dfeSToby Isaac PetscDTJacobiNorm - Compute the weighted L2 norm of a Jacobi polynomial. 648fbdc3dfeSToby Isaac 649fbdc3dfeSToby Isaac $\| P^{\alpha,\beta}_n \|_{\alpha,\beta}^2 = \int_{-1}^1 (1 + x)^{\alpha} (1 - x)^{\beta} P^{\alpha,\beta}_n (x)^2 dx.$ 650fbdc3dfeSToby Isaac 6514165533cSJose E. Roman Input Parameters: 652fbdc3dfeSToby Isaac - alpha - the left exponent > -1 653fbdc3dfeSToby Isaac . beta - the right exponent > -1 654fbdc3dfeSToby Isaac + n - the polynomial degree 655fbdc3dfeSToby Isaac 6564165533cSJose E. Roman Output Parameter: 657fbdc3dfeSToby Isaac . norm - the weighted L2 norm 658fbdc3dfeSToby Isaac 659fbdc3dfeSToby Isaac Level: beginner 660fbdc3dfeSToby Isaac 661db781477SPatrick Sanan .seealso: `PetscDTJacobiEval()` 662fbdc3dfeSToby Isaac @*/ 6639371c9d4SSatish Balay PetscErrorCode PetscDTJacobiNorm(PetscReal alpha, PetscReal beta, PetscInt n, PetscReal *norm) { 664fbdc3dfeSToby Isaac PetscReal twoab1; 665fbdc3dfeSToby Isaac PetscReal gr; 666fbdc3dfeSToby Isaac 667fbdc3dfeSToby Isaac PetscFunctionBegin; 66808401ef6SPierre Jolivet PetscCheck(alpha > -1., PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Exponent alpha %g <= -1. invalid", (double)alpha); 66908401ef6SPierre Jolivet PetscCheck(beta > -1., PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Exponent beta %g <= -1. invalid", (double)beta); 67063a3b9bcSJacob Faibussowitsch PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "n %" PetscInt_FMT " < 0 invalid", n); 671fbdc3dfeSToby Isaac twoab1 = PetscPowReal(2., alpha + beta + 1.); 672fbdc3dfeSToby Isaac #if defined(PETSC_HAVE_LGAMMA) 673fbdc3dfeSToby Isaac if (!n) { 674fbdc3dfeSToby Isaac gr = PetscExpReal(PetscLGamma(alpha + 1.) + PetscLGamma(beta + 1.) - PetscLGamma(alpha + beta + 2.)); 675fbdc3dfeSToby Isaac } else { 676fbdc3dfeSToby Isaac gr = PetscExpReal(PetscLGamma(n + alpha + 1.) + PetscLGamma(n + beta + 1.) - (PetscLGamma(n + 1.) + PetscLGamma(n + alpha + beta + 1.))) / (n + n + alpha + beta + 1.); 677fbdc3dfeSToby Isaac } 678fbdc3dfeSToby Isaac #else 679fbdc3dfeSToby Isaac { 680fbdc3dfeSToby Isaac PetscInt alphai = (PetscInt)alpha; 681fbdc3dfeSToby Isaac PetscInt betai = (PetscInt)beta; 682fbdc3dfeSToby Isaac PetscInt i; 683fbdc3dfeSToby Isaac 684fbdc3dfeSToby Isaac gr = n ? (1. / (n + n + alpha + beta + 1.)) : 1.; 685fbdc3dfeSToby Isaac if ((PetscReal)alphai == alpha) { 686fbdc3dfeSToby Isaac if (!n) { 687fbdc3dfeSToby Isaac for (i = 0; i < alphai; i++) gr *= (i + 1.) / (beta + i + 1.); 688fbdc3dfeSToby Isaac gr /= (alpha + beta + 1.); 689fbdc3dfeSToby Isaac } else { 690fbdc3dfeSToby Isaac for (i = 0; i < alphai; i++) gr *= (n + i + 1.) / (n + beta + i + 1.); 691fbdc3dfeSToby Isaac } 692fbdc3dfeSToby Isaac } else if ((PetscReal)betai == beta) { 693fbdc3dfeSToby Isaac if (!n) { 694fbdc3dfeSToby Isaac for (i = 0; i < betai; i++) gr *= (i + 1.) / (alpha + i + 2.); 695fbdc3dfeSToby Isaac gr /= (alpha + beta + 1.); 696fbdc3dfeSToby Isaac } else { 697fbdc3dfeSToby Isaac for (i = 0; i < betai; i++) gr *= (n + i + 1.) / (n + alpha + i + 1.); 698fbdc3dfeSToby Isaac } 699fbdc3dfeSToby Isaac } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "lgamma() - math routine is unavailable."); 700fbdc3dfeSToby Isaac } 701fbdc3dfeSToby Isaac #endif 702fbdc3dfeSToby Isaac *norm = PetscSqrtReal(twoab1 * gr); 703fbdc3dfeSToby Isaac PetscFunctionReturn(0); 704fbdc3dfeSToby Isaac } 705fbdc3dfeSToby Isaac 7069371c9d4SSatish Balay static PetscErrorCode PetscDTJacobiEval_Internal(PetscInt npoints, PetscReal a, PetscReal b, PetscInt k, const PetscReal *points, PetscInt ndegree, const PetscInt *degrees, PetscReal *p) { 70794e21283SToby Isaac PetscReal ak, bk; 70894e21283SToby Isaac PetscReal abk1; 70994e21283SToby Isaac PetscInt i, l, maxdegree; 71094e21283SToby Isaac 71194e21283SToby Isaac PetscFunctionBegin; 71294e21283SToby Isaac maxdegree = degrees[ndegree - 1] - k; 71394e21283SToby Isaac ak = a + k; 71494e21283SToby Isaac bk = b + k; 71594e21283SToby Isaac abk1 = a + b + k + 1.; 71694e21283SToby Isaac if (maxdegree < 0) { 7179371c9d4SSatish Balay for (i = 0; i < npoints; i++) 7189371c9d4SSatish Balay for (l = 0; l < ndegree; l++) p[i * ndegree + l] = 0.; 71994e21283SToby Isaac PetscFunctionReturn(0); 72094e21283SToby Isaac } 72194e21283SToby Isaac for (i = 0; i < npoints; i++) { 72294e21283SToby Isaac PetscReal pm1, pm2, x; 72394e21283SToby Isaac PetscReal cnm1, cnm1x, cnm2; 72494e21283SToby Isaac PetscInt j, m; 72594e21283SToby Isaac 72694e21283SToby Isaac x = points[i]; 72794e21283SToby Isaac pm2 = 1.; 72894e21283SToby Isaac PetscDTJacobiRecurrence_Internal(1, ak, bk, cnm1, cnm1x, cnm2); 72994e21283SToby Isaac pm1 = (cnm1 + cnm1x * x); 73094e21283SToby Isaac l = 0; 7319371c9d4SSatish Balay while (l < ndegree && degrees[l] - k < 0) { p[l++] = 0.; } 73294e21283SToby Isaac while (l < ndegree && degrees[l] - k == 0) { 73394e21283SToby Isaac p[l] = pm2; 73494e21283SToby Isaac for (m = 0; m < k; m++) p[l] *= (abk1 + m) * 0.5; 73594e21283SToby Isaac l++; 73694e21283SToby Isaac } 73794e21283SToby Isaac while (l < ndegree && degrees[l] - k == 1) { 73894e21283SToby Isaac p[l] = pm1; 73994e21283SToby Isaac for (m = 0; m < k; m++) p[l] *= (abk1 + 1 + m) * 0.5; 74094e21283SToby Isaac l++; 74194e21283SToby Isaac } 74294e21283SToby Isaac for (j = 2; j <= maxdegree; j++) { 74394e21283SToby Isaac PetscReal pp; 74494e21283SToby Isaac 74594e21283SToby Isaac PetscDTJacobiRecurrence_Internal(j, ak, bk, cnm1, cnm1x, cnm2); 74694e21283SToby Isaac pp = (cnm1 + cnm1x * x) * pm1 - cnm2 * pm2; 74794e21283SToby Isaac pm2 = pm1; 74894e21283SToby Isaac pm1 = pp; 74994e21283SToby Isaac while (l < ndegree && degrees[l] - k == j) { 75094e21283SToby Isaac p[l] = pp; 75194e21283SToby Isaac for (m = 0; m < k; m++) p[l] *= (abk1 + j + m) * 0.5; 75294e21283SToby Isaac l++; 75394e21283SToby Isaac } 75494e21283SToby Isaac } 75594e21283SToby Isaac p += ndegree; 75694e21283SToby Isaac } 75794e21283SToby Isaac PetscFunctionReturn(0); 75894e21283SToby Isaac } 75994e21283SToby Isaac 76037045ce4SJed Brown /*@ 761fbdc3dfeSToby 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$. 762fbdc3dfeSToby Isaac 7634165533cSJose E. Roman Input Parameters: 764fbdc3dfeSToby Isaac + alpha - the left exponent of the weight 765fbdc3dfeSToby Isaac . beta - the right exponetn of the weight 766fbdc3dfeSToby Isaac . npoints - the number of points to evaluate the polynomials at 767fbdc3dfeSToby Isaac . points - [npoints] array of point coordinates 768fbdc3dfeSToby Isaac . degree - the maximm degree polynomial space to evaluate, (degree + 1) will be evaluated total. 769fbdc3dfeSToby Isaac - k - the maximum derivative to evaluate in the jet, (k + 1) will be evaluated total. 770fbdc3dfeSToby Isaac 7716aad120cSJose E. Roman Output Parameters: 772fbdc3dfeSToby Isaac - p - an array containing the evaluations of the Jacobi polynomials's jets on the points. the size is (degree + 1) x 773fbdc3dfeSToby Isaac (k + 1) x npoints, which also describes the order of the dimensions of this three-dimensional array: the first 774fbdc3dfeSToby Isaac (slowest varying) dimension is polynomial degree; the second dimension is derivative order; the third (fastest 775fbdc3dfeSToby Isaac varying) dimension is the index of the evaluation point. 776fbdc3dfeSToby Isaac 777fbdc3dfeSToby Isaac Level: advanced 778fbdc3dfeSToby Isaac 779db781477SPatrick Sanan .seealso: `PetscDTJacobiEval()`, `PetscDTPKDEvalJet()` 780fbdc3dfeSToby Isaac @*/ 7819371c9d4SSatish Balay PetscErrorCode PetscDTJacobiEvalJet(PetscReal alpha, PetscReal beta, PetscInt npoints, const PetscReal points[], PetscInt degree, PetscInt k, PetscReal p[]) { 782fbdc3dfeSToby Isaac PetscInt i, j, l; 783fbdc3dfeSToby Isaac PetscInt *degrees; 784fbdc3dfeSToby Isaac PetscReal *psingle; 785fbdc3dfeSToby Isaac 786fbdc3dfeSToby Isaac PetscFunctionBegin; 787fbdc3dfeSToby Isaac if (degree == 0) { 788fbdc3dfeSToby Isaac PetscInt zero = 0; 789fbdc3dfeSToby Isaac 790*48a46eb9SPierre Jolivet for (i = 0; i <= k; i++) PetscCall(PetscDTJacobiEval_Internal(npoints, alpha, beta, i, points, 1, &zero, &p[i * npoints])); 791fbdc3dfeSToby Isaac PetscFunctionReturn(0); 792fbdc3dfeSToby Isaac } 7939566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(degree + 1, °rees)); 7949566063dSJacob Faibussowitsch PetscCall(PetscMalloc1((degree + 1) * npoints, &psingle)); 795fbdc3dfeSToby Isaac for (i = 0; i <= degree; i++) degrees[i] = i; 796fbdc3dfeSToby Isaac for (i = 0; i <= k; i++) { 7979566063dSJacob Faibussowitsch PetscCall(PetscDTJacobiEval_Internal(npoints, alpha, beta, i, points, degree + 1, degrees, psingle)); 798fbdc3dfeSToby Isaac for (j = 0; j <= degree; j++) { 7999371c9d4SSatish Balay for (l = 0; l < npoints; l++) { p[(j * (k + 1) + i) * npoints + l] = psingle[l * (degree + 1) + j]; } 800fbdc3dfeSToby Isaac } 801fbdc3dfeSToby Isaac } 8029566063dSJacob Faibussowitsch PetscCall(PetscFree(psingle)); 8039566063dSJacob Faibussowitsch PetscCall(PetscFree(degrees)); 804fbdc3dfeSToby Isaac PetscFunctionReturn(0); 805fbdc3dfeSToby Isaac } 806fbdc3dfeSToby Isaac 807fbdc3dfeSToby Isaac /*@ 80894e21283SToby Isaac PetscDTJacobiEval - evaluate Jacobi polynomials for the weight function $(1.+x)^{\alpha} (1.-x)^{\beta}$ 80994e21283SToby Isaac at points 81094e21283SToby Isaac 81194e21283SToby Isaac Not Collective 81294e21283SToby Isaac 8134165533cSJose E. Roman Input Parameters: 81494e21283SToby Isaac + npoints - number of spatial points to evaluate at 81594e21283SToby Isaac . alpha - the left exponent > -1 81694e21283SToby Isaac . beta - the right exponent > -1 81794e21283SToby Isaac . points - array of locations to evaluate at 81894e21283SToby Isaac . ndegree - number of basis degrees to evaluate 81994e21283SToby Isaac - degrees - sorted array of degrees to evaluate 82094e21283SToby Isaac 8214165533cSJose E. Roman Output Parameters: 82294e21283SToby Isaac + B - row-oriented basis evaluation matrix B[point*ndegree + degree] (dimension npoints*ndegrees, allocated by caller) (or NULL) 82394e21283SToby Isaac . D - row-oriented derivative evaluation matrix (or NULL) 82494e21283SToby Isaac - D2 - row-oriented second derivative evaluation matrix (or NULL) 82594e21283SToby Isaac 82694e21283SToby Isaac Level: intermediate 82794e21283SToby Isaac 828db781477SPatrick Sanan .seealso: `PetscDTGaussQuadrature()` 82994e21283SToby Isaac @*/ 8309371c9d4SSatish Balay PetscErrorCode PetscDTJacobiEval(PetscInt npoints, PetscReal alpha, PetscReal beta, const PetscReal *points, PetscInt ndegree, const PetscInt *degrees, PetscReal *B, PetscReal *D, PetscReal *D2) { 83194e21283SToby Isaac PetscFunctionBegin; 83208401ef6SPierre Jolivet PetscCheck(alpha > -1., PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "alpha must be > -1."); 83308401ef6SPierre Jolivet PetscCheck(beta > -1., PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "beta must be > -1."); 83494e21283SToby Isaac if (!npoints || !ndegree) PetscFunctionReturn(0); 8359566063dSJacob Faibussowitsch if (B) PetscCall(PetscDTJacobiEval_Internal(npoints, alpha, beta, 0, points, ndegree, degrees, B)); 8369566063dSJacob Faibussowitsch if (D) PetscCall(PetscDTJacobiEval_Internal(npoints, alpha, beta, 1, points, ndegree, degrees, D)); 8379566063dSJacob Faibussowitsch if (D2) PetscCall(PetscDTJacobiEval_Internal(npoints, alpha, beta, 2, points, ndegree, degrees, D2)); 83894e21283SToby Isaac PetscFunctionReturn(0); 83994e21283SToby Isaac } 84094e21283SToby Isaac 84194e21283SToby Isaac /*@ 84294e21283SToby Isaac PetscDTLegendreEval - evaluate Legendre polynomials at points 84337045ce4SJed Brown 84437045ce4SJed Brown Not Collective 84537045ce4SJed Brown 8464165533cSJose E. Roman Input Parameters: 84737045ce4SJed Brown + npoints - number of spatial points to evaluate at 84837045ce4SJed Brown . points - array of locations to evaluate at 84937045ce4SJed Brown . ndegree - number of basis degrees to evaluate 85037045ce4SJed Brown - degrees - sorted array of degrees to evaluate 85137045ce4SJed Brown 8524165533cSJose E. Roman Output Parameters: 8530298fd71SBarry Smith + B - row-oriented basis evaluation matrix B[point*ndegree + degree] (dimension npoints*ndegrees, allocated by caller) (or NULL) 8540298fd71SBarry Smith . D - row-oriented derivative evaluation matrix (or NULL) 8550298fd71SBarry Smith - D2 - row-oriented second derivative evaluation matrix (or NULL) 85637045ce4SJed Brown 85737045ce4SJed Brown Level: intermediate 85837045ce4SJed Brown 859db781477SPatrick Sanan .seealso: `PetscDTGaussQuadrature()` 86037045ce4SJed Brown @*/ 8619371c9d4SSatish Balay PetscErrorCode PetscDTLegendreEval(PetscInt npoints, const PetscReal *points, PetscInt ndegree, const PetscInt *degrees, PetscReal *B, PetscReal *D, PetscReal *D2) { 86237045ce4SJed Brown PetscFunctionBegin; 8639566063dSJacob Faibussowitsch PetscCall(PetscDTJacobiEval(npoints, 0., 0., points, ndegree, degrees, B, D, D2)); 86437045ce4SJed Brown PetscFunctionReturn(0); 86537045ce4SJed Brown } 86637045ce4SJed Brown 867fbdc3dfeSToby Isaac /*@ 868fbdc3dfeSToby 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) 869fbdc3dfeSToby Isaac 870fbdc3dfeSToby Isaac Input Parameters: 871fbdc3dfeSToby Isaac + len - the desired length of the degree tuple 872fbdc3dfeSToby Isaac - index - the index to convert: should be >= 0 873fbdc3dfeSToby Isaac 874fbdc3dfeSToby Isaac Output Parameter: 875fbdc3dfeSToby Isaac . degtup - will be filled with a tuple of degrees 876fbdc3dfeSToby Isaac 877fbdc3dfeSToby Isaac Level: beginner 878fbdc3dfeSToby Isaac 879fbdc3dfeSToby Isaac Note: for two tuples x and y with the same degree sum, partial degree sums over the final elements of the tuples 880fbdc3dfeSToby 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 881fbdc3dfeSToby Isaac last two elements is smaller for the former, so (2, 1, 1) < (1, 2, 1). 882fbdc3dfeSToby Isaac 883db781477SPatrick Sanan .seealso: `PetscDTGradedOrderToIndex()` 884fbdc3dfeSToby Isaac @*/ 8859371c9d4SSatish Balay PetscErrorCode PetscDTIndexToGradedOrder(PetscInt len, PetscInt index, PetscInt degtup[]) { 886fbdc3dfeSToby Isaac PetscInt i, total; 887fbdc3dfeSToby Isaac PetscInt sum; 888fbdc3dfeSToby Isaac 889fbdc3dfeSToby Isaac PetscFunctionBeginHot; 89008401ef6SPierre Jolivet PetscCheck(len >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "length must be non-negative"); 89108401ef6SPierre Jolivet PetscCheck(index >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "index must be non-negative"); 892fbdc3dfeSToby Isaac total = 1; 893fbdc3dfeSToby Isaac sum = 0; 894fbdc3dfeSToby Isaac while (index >= total) { 895fbdc3dfeSToby Isaac index -= total; 896fbdc3dfeSToby Isaac total = (total * (len + sum)) / (sum + 1); 897fbdc3dfeSToby Isaac sum++; 898fbdc3dfeSToby Isaac } 899fbdc3dfeSToby Isaac for (i = 0; i < len; i++) { 900fbdc3dfeSToby Isaac PetscInt c; 901fbdc3dfeSToby Isaac 902fbdc3dfeSToby Isaac degtup[i] = sum; 903fbdc3dfeSToby Isaac for (c = 0, total = 1; c < sum; c++) { 904fbdc3dfeSToby Isaac /* going into the loop, total is the number of way to have a tuple of sum exactly c with length len - 1 - i */ 905fbdc3dfeSToby Isaac if (index < total) break; 906fbdc3dfeSToby Isaac index -= total; 907fbdc3dfeSToby Isaac total = (total * (len - 1 - i + c)) / (c + 1); 908fbdc3dfeSToby Isaac degtup[i]--; 909fbdc3dfeSToby Isaac } 910fbdc3dfeSToby Isaac sum -= degtup[i]; 911fbdc3dfeSToby Isaac } 912fbdc3dfeSToby Isaac PetscFunctionReturn(0); 913fbdc3dfeSToby Isaac } 914fbdc3dfeSToby Isaac 915fbdc3dfeSToby Isaac /*@ 916fbdc3dfeSToby Isaac PetscDTGradedOrderToIndex - convert a tuple into an index in a graded order, the inverse of PetscDTIndexToGradedOrder(). 917fbdc3dfeSToby Isaac 918fbdc3dfeSToby Isaac Input Parameters: 919fbdc3dfeSToby Isaac + len - the length of the degree tuple 920fbdc3dfeSToby Isaac - degtup - tuple with this length 921fbdc3dfeSToby Isaac 922fbdc3dfeSToby Isaac Output Parameter: 923fbdc3dfeSToby Isaac . index - index in graded order: >= 0 924fbdc3dfeSToby Isaac 925fbdc3dfeSToby Isaac Level: Beginner 926fbdc3dfeSToby Isaac 927fbdc3dfeSToby Isaac Note: for two tuples x and y with the same degree sum, partial degree sums over the final elements of the tuples 928fbdc3dfeSToby 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 929fbdc3dfeSToby Isaac last two elements is smaller for the former, so (2, 1, 1) < (1, 2, 1). 930fbdc3dfeSToby Isaac 931db781477SPatrick Sanan .seealso: `PetscDTIndexToGradedOrder()` 932fbdc3dfeSToby Isaac @*/ 9339371c9d4SSatish Balay PetscErrorCode PetscDTGradedOrderToIndex(PetscInt len, const PetscInt degtup[], PetscInt *index) { 934fbdc3dfeSToby Isaac PetscInt i, idx, sum, total; 935fbdc3dfeSToby Isaac 936fbdc3dfeSToby Isaac PetscFunctionBeginHot; 93708401ef6SPierre Jolivet PetscCheck(len >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "length must be non-negative"); 938fbdc3dfeSToby Isaac for (i = 0, sum = 0; i < len; i++) sum += degtup[i]; 939fbdc3dfeSToby Isaac idx = 0; 940fbdc3dfeSToby Isaac total = 1; 941fbdc3dfeSToby Isaac for (i = 0; i < sum; i++) { 942fbdc3dfeSToby Isaac idx += total; 943fbdc3dfeSToby Isaac total = (total * (len + i)) / (i + 1); 944fbdc3dfeSToby Isaac } 945fbdc3dfeSToby Isaac for (i = 0; i < len - 1; i++) { 946fbdc3dfeSToby Isaac PetscInt c; 947fbdc3dfeSToby Isaac 948fbdc3dfeSToby Isaac total = 1; 949fbdc3dfeSToby Isaac sum -= degtup[i]; 950fbdc3dfeSToby Isaac for (c = 0; c < sum; c++) { 951fbdc3dfeSToby Isaac idx += total; 952fbdc3dfeSToby Isaac total = (total * (len - 1 - i + c)) / (c + 1); 953fbdc3dfeSToby Isaac } 954fbdc3dfeSToby Isaac } 955fbdc3dfeSToby Isaac *index = idx; 956fbdc3dfeSToby Isaac PetscFunctionReturn(0); 957fbdc3dfeSToby Isaac } 958fbdc3dfeSToby Isaac 959e3aa2e09SToby Isaac static PetscBool PKDCite = PETSC_FALSE; 960e3aa2e09SToby Isaac const char PKDCitation[] = "@article{Kirby2010,\n" 961e3aa2e09SToby Isaac " title={Singularity-free evaluation of collapsed-coordinate orthogonal polynomials},\n" 962e3aa2e09SToby Isaac " author={Kirby, Robert C},\n" 963e3aa2e09SToby Isaac " journal={ACM Transactions on Mathematical Software (TOMS)},\n" 964e3aa2e09SToby Isaac " volume={37},\n" 965e3aa2e09SToby Isaac " number={1},\n" 966e3aa2e09SToby Isaac " pages={1--16},\n" 967e3aa2e09SToby Isaac " year={2010},\n" 968e3aa2e09SToby Isaac " publisher={ACM New York, NY, USA}\n}\n"; 969e3aa2e09SToby Isaac 970fbdc3dfeSToby Isaac /*@ 971d8f25ad8SToby Isaac PetscDTPKDEvalJet - Evaluate the jet (function and derivatives) of the Proriol-Koornwinder-Dubiner (PKD) basis for 972fbdc3dfeSToby Isaac the space of polynomials up to a given degree. The PKD basis is L2-orthonormal on the biunit simplex (which is used 973fbdc3dfeSToby Isaac as the reference element for finite elements in PETSc), which makes it a stable basis to use for evaluating 974fbdc3dfeSToby Isaac polynomials in that domain. 975fbdc3dfeSToby Isaac 9764165533cSJose E. Roman Input Parameters: 977fbdc3dfeSToby Isaac + dim - the number of variables in the multivariate polynomials 978fbdc3dfeSToby Isaac . npoints - the number of points to evaluate the polynomials at 979fbdc3dfeSToby Isaac . points - [npoints x dim] array of point coordinates 980fbdc3dfeSToby 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. 981fbdc3dfeSToby Isaac - k - the maximum order partial derivative to evaluate in the jet. There are (dim + k choose dim) partial derivatives 982fbdc3dfeSToby Isaac in the jet. Choosing k = 0 means to evaluate just the function and no derivatives 983fbdc3dfeSToby Isaac 9846aad120cSJose E. Roman Output Parameters: 985fbdc3dfeSToby Isaac - p - an array containing the evaluations of the PKD polynomials' jets on the points. The size is ((dim + degree) 986fbdc3dfeSToby Isaac choose dim) x ((dim + k) choose dim) x npoints, which also describes the order of the dimensions of this 987fbdc3dfeSToby Isaac three-dimensional array: the first (slowest varying) dimension is basis function index; the second dimension is jet 988fbdc3dfeSToby Isaac index; the third (fastest varying) dimension is the index of the evaluation point. 989fbdc3dfeSToby Isaac 990fbdc3dfeSToby Isaac Level: advanced 991fbdc3dfeSToby Isaac 992fbdc3dfeSToby Isaac Note: The ordering of the basis functions, and the ordering of the derivatives in the jet, both follow the graded 993fbdc3dfeSToby Isaac ordering of PetscDTIndexToGradedOrder() and PetscDTGradedOrderToIndex(). For example, in 3D, the polynomial with 994d8f25ad8SToby 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); 995fbdc3dfeSToby 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). 996fbdc3dfeSToby Isaac 997e3aa2e09SToby Isaac The implementation uses Kirby's singularity-free evaluation algorithm, https://doi.org/10.1145/1644001.1644006. 998e3aa2e09SToby Isaac 999db781477SPatrick Sanan .seealso: `PetscDTGradedOrderToIndex()`, `PetscDTIndexToGradedOrder()`, `PetscDTJacobiEvalJet()` 1000fbdc3dfeSToby Isaac @*/ 10019371c9d4SSatish Balay PetscErrorCode PetscDTPKDEvalJet(PetscInt dim, PetscInt npoints, const PetscReal points[], PetscInt degree, PetscInt k, PetscReal p[]) { 1002fbdc3dfeSToby Isaac PetscInt degidx, kidx, d, pt; 1003fbdc3dfeSToby Isaac PetscInt Nk, Ndeg; 1004fbdc3dfeSToby Isaac PetscInt *ktup, *degtup; 1005fbdc3dfeSToby Isaac PetscReal *scales, initscale, scaleexp; 1006fbdc3dfeSToby Isaac 1007fbdc3dfeSToby Isaac PetscFunctionBegin; 10089566063dSJacob Faibussowitsch PetscCall(PetscCitationsRegister(PKDCitation, &PKDCite)); 10099566063dSJacob Faibussowitsch PetscCall(PetscDTBinomialInt(dim + k, k, &Nk)); 10109566063dSJacob Faibussowitsch PetscCall(PetscDTBinomialInt(degree + dim, degree, &Ndeg)); 10119566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(dim, °tup, dim, &ktup)); 10129566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(Ndeg, &scales)); 1013fbdc3dfeSToby Isaac initscale = 1.; 1014fbdc3dfeSToby Isaac if (dim > 1) { 10159566063dSJacob Faibussowitsch PetscCall(PetscDTBinomial(dim, 2, &scaleexp)); 10162f613bf5SBarry Smith initscale = PetscPowReal(2., scaleexp * 0.5); 1017fbdc3dfeSToby Isaac } 1018fbdc3dfeSToby Isaac for (degidx = 0; degidx < Ndeg; degidx++) { 1019fbdc3dfeSToby Isaac PetscInt e, i; 1020fbdc3dfeSToby Isaac PetscInt m1idx = -1, m2idx = -1; 1021fbdc3dfeSToby Isaac PetscInt n; 1022fbdc3dfeSToby Isaac PetscInt degsum; 1023fbdc3dfeSToby Isaac PetscReal alpha; 1024fbdc3dfeSToby Isaac PetscReal cnm1, cnm1x, cnm2; 1025fbdc3dfeSToby Isaac PetscReal norm; 1026fbdc3dfeSToby Isaac 10279566063dSJacob Faibussowitsch PetscCall(PetscDTIndexToGradedOrder(dim, degidx, degtup)); 10289371c9d4SSatish Balay for (d = dim - 1; d >= 0; d--) 10299371c9d4SSatish Balay if (degtup[d]) break; 1030fbdc3dfeSToby Isaac if (d < 0) { /* constant is 1 everywhere, all derivatives are zero */ 1031fbdc3dfeSToby Isaac scales[degidx] = initscale; 1032fbdc3dfeSToby Isaac for (e = 0; e < dim; e++) { 10339566063dSJacob Faibussowitsch PetscCall(PetscDTJacobiNorm(e, 0., 0, &norm)); 1034fbdc3dfeSToby Isaac scales[degidx] /= norm; 1035fbdc3dfeSToby Isaac } 1036fbdc3dfeSToby Isaac for (i = 0; i < npoints; i++) p[degidx * Nk * npoints + i] = 1.; 1037fbdc3dfeSToby Isaac for (i = 0; i < (Nk - 1) * npoints; i++) p[(degidx * Nk + 1) * npoints + i] = 0.; 1038fbdc3dfeSToby Isaac continue; 1039fbdc3dfeSToby Isaac } 1040fbdc3dfeSToby Isaac n = degtup[d]; 1041fbdc3dfeSToby Isaac degtup[d]--; 10429566063dSJacob Faibussowitsch PetscCall(PetscDTGradedOrderToIndex(dim, degtup, &m1idx)); 1043fbdc3dfeSToby Isaac if (degtup[d] > 0) { 1044fbdc3dfeSToby Isaac degtup[d]--; 10459566063dSJacob Faibussowitsch PetscCall(PetscDTGradedOrderToIndex(dim, degtup, &m2idx)); 1046fbdc3dfeSToby Isaac degtup[d]++; 1047fbdc3dfeSToby Isaac } 1048fbdc3dfeSToby Isaac degtup[d]++; 1049fbdc3dfeSToby Isaac for (e = 0, degsum = 0; e < d; e++) degsum += degtup[e]; 1050fbdc3dfeSToby Isaac alpha = 2 * degsum + d; 1051fbdc3dfeSToby Isaac PetscDTJacobiRecurrence_Internal(n, alpha, 0., cnm1, cnm1x, cnm2); 1052fbdc3dfeSToby Isaac 1053fbdc3dfeSToby Isaac scales[degidx] = initscale; 1054fbdc3dfeSToby Isaac for (e = 0, degsum = 0; e < dim; e++) { 1055fbdc3dfeSToby Isaac PetscInt f; 1056fbdc3dfeSToby Isaac PetscReal ealpha; 1057fbdc3dfeSToby Isaac PetscReal enorm; 1058fbdc3dfeSToby Isaac 1059fbdc3dfeSToby Isaac ealpha = 2 * degsum + e; 1060fbdc3dfeSToby Isaac for (f = 0; f < degsum; f++) scales[degidx] *= 2.; 10619566063dSJacob Faibussowitsch PetscCall(PetscDTJacobiNorm(ealpha, 0., degtup[e], &enorm)); 1062fbdc3dfeSToby Isaac scales[degidx] /= enorm; 1063fbdc3dfeSToby Isaac degsum += degtup[e]; 1064fbdc3dfeSToby Isaac } 1065fbdc3dfeSToby Isaac 1066fbdc3dfeSToby Isaac for (pt = 0; pt < npoints; pt++) { 1067fbdc3dfeSToby Isaac /* compute the multipliers */ 1068fbdc3dfeSToby Isaac PetscReal thetanm1, thetanm1x, thetanm2; 1069fbdc3dfeSToby Isaac 1070fbdc3dfeSToby Isaac thetanm1x = dim - (d + 1) + 2. * points[pt * dim + d]; 1071fbdc3dfeSToby Isaac for (e = d + 1; e < dim; e++) thetanm1x += points[pt * dim + e]; 1072fbdc3dfeSToby Isaac thetanm1x *= 0.5; 1073fbdc3dfeSToby Isaac thetanm1 = (2. - (dim - (d + 1))); 1074fbdc3dfeSToby Isaac for (e = d + 1; e < dim; e++) thetanm1 -= points[pt * dim + e]; 1075fbdc3dfeSToby Isaac thetanm1 *= 0.5; 1076fbdc3dfeSToby Isaac thetanm2 = thetanm1 * thetanm1; 1077fbdc3dfeSToby Isaac 1078fbdc3dfeSToby Isaac for (kidx = 0; kidx < Nk; kidx++) { 1079fbdc3dfeSToby Isaac PetscInt f; 1080fbdc3dfeSToby Isaac 10819566063dSJacob Faibussowitsch PetscCall(PetscDTIndexToGradedOrder(dim, kidx, ktup)); 1082fbdc3dfeSToby Isaac /* first sum in the same derivative terms */ 1083fbdc3dfeSToby Isaac p[(degidx * Nk + kidx) * npoints + pt] = (cnm1 * thetanm1 + cnm1x * thetanm1x) * p[(m1idx * Nk + kidx) * npoints + pt]; 10849371c9d4SSatish Balay if (m2idx >= 0) { p[(degidx * Nk + kidx) * npoints + pt] -= cnm2 * thetanm2 * p[(m2idx * Nk + kidx) * npoints + pt]; } 1085fbdc3dfeSToby Isaac 1086fbdc3dfeSToby Isaac for (f = d; f < dim; f++) { 1087fbdc3dfeSToby Isaac PetscInt km1idx, mplty = ktup[f]; 1088fbdc3dfeSToby Isaac 1089fbdc3dfeSToby Isaac if (!mplty) continue; 1090fbdc3dfeSToby Isaac ktup[f]--; 10919566063dSJacob Faibussowitsch PetscCall(PetscDTGradedOrderToIndex(dim, ktup, &km1idx)); 1092fbdc3dfeSToby Isaac 1093fbdc3dfeSToby Isaac /* the derivative of cnm1x * thetanm1x wrt x variable f is 0.5 * cnm1x if f > d otherwise it is cnm1x */ 1094fbdc3dfeSToby Isaac /* the derivative of cnm1 * thetanm1 wrt x variable f is 0 if f == d, otherwise it is -0.5 * cnm1 */ 1095fbdc3dfeSToby Isaac /* the derivative of -cnm2 * thetanm2 wrt x variable f is 0 if f == d, otherwise it is cnm2 * thetanm1 */ 1096fbdc3dfeSToby Isaac if (f > d) { 1097fbdc3dfeSToby Isaac PetscInt f2; 1098fbdc3dfeSToby Isaac 1099fbdc3dfeSToby Isaac p[(degidx * Nk + kidx) * npoints + pt] += mplty * 0.5 * (cnm1x - cnm1) * p[(m1idx * Nk + km1idx) * npoints + pt]; 1100fbdc3dfeSToby Isaac if (m2idx >= 0) { 1101fbdc3dfeSToby Isaac p[(degidx * Nk + kidx) * npoints + pt] += mplty * cnm2 * thetanm1 * p[(m2idx * Nk + km1idx) * npoints + pt]; 1102fbdc3dfeSToby Isaac /* second derivatives of -cnm2 * thetanm2 wrt x variable f,f2 is like - 0.5 * cnm2 */ 1103fbdc3dfeSToby Isaac for (f2 = f; f2 < dim; f2++) { 1104fbdc3dfeSToby Isaac PetscInt km2idx, mplty2 = ktup[f2]; 1105fbdc3dfeSToby Isaac PetscInt factor; 1106fbdc3dfeSToby Isaac 1107fbdc3dfeSToby Isaac if (!mplty2) continue; 1108fbdc3dfeSToby Isaac ktup[f2]--; 11099566063dSJacob Faibussowitsch PetscCall(PetscDTGradedOrderToIndex(dim, ktup, &km2idx)); 1110fbdc3dfeSToby Isaac 1111fbdc3dfeSToby Isaac factor = mplty * mplty2; 1112fbdc3dfeSToby Isaac if (f == f2) factor /= 2; 1113fbdc3dfeSToby Isaac p[(degidx * Nk + kidx) * npoints + pt] -= 0.5 * factor * cnm2 * p[(m2idx * Nk + km2idx) * npoints + pt]; 1114fbdc3dfeSToby Isaac ktup[f2]++; 1115fbdc3dfeSToby Isaac } 11163034baaeSToby Isaac } 1117fbdc3dfeSToby Isaac } else { 1118fbdc3dfeSToby Isaac p[(degidx * Nk + kidx) * npoints + pt] += mplty * cnm1x * p[(m1idx * Nk + km1idx) * npoints + pt]; 1119fbdc3dfeSToby Isaac } 1120fbdc3dfeSToby Isaac ktup[f]++; 1121fbdc3dfeSToby Isaac } 1122fbdc3dfeSToby Isaac } 1123fbdc3dfeSToby Isaac } 1124fbdc3dfeSToby Isaac } 1125fbdc3dfeSToby Isaac for (degidx = 0; degidx < Ndeg; degidx++) { 1126fbdc3dfeSToby Isaac PetscReal scale = scales[degidx]; 1127fbdc3dfeSToby Isaac PetscInt i; 1128fbdc3dfeSToby Isaac 1129fbdc3dfeSToby Isaac for (i = 0; i < Nk * npoints; i++) p[degidx * Nk * npoints + i] *= scale; 1130fbdc3dfeSToby Isaac } 11319566063dSJacob Faibussowitsch PetscCall(PetscFree(scales)); 11329566063dSJacob Faibussowitsch PetscCall(PetscFree2(degtup, ktup)); 1133fbdc3dfeSToby Isaac PetscFunctionReturn(0); 1134fbdc3dfeSToby Isaac } 1135fbdc3dfeSToby Isaac 1136d8f25ad8SToby Isaac /*@ 1137d8f25ad8SToby Isaac PetscDTPTrimmedSize - The size of the trimmed polynomial space of k-forms with a given degree and form degree, 1138d8f25ad8SToby Isaac which can be evaluated in PetscDTPTrimmedEvalJet(). 1139d8f25ad8SToby Isaac 1140d8f25ad8SToby Isaac Input Parameters: 1141d8f25ad8SToby Isaac + dim - the number of variables in the multivariate polynomials 1142d8f25ad8SToby Isaac . degree - the degree (sum of degrees on the variables in a monomial) of the trimmed polynomial space. 1143d8f25ad8SToby Isaac - formDegree - the degree of the form 1144d8f25ad8SToby Isaac 11456aad120cSJose E. Roman Output Parameters: 1146d8f25ad8SToby Isaac - size - The number ((dim + degree) choose (dim + formDegree)) x ((degree + formDegree - 1) choose (formDegree)) 1147d8f25ad8SToby Isaac 1148d8f25ad8SToby Isaac Level: advanced 1149d8f25ad8SToby Isaac 1150db781477SPatrick Sanan .seealso: `PetscDTPTrimmedEvalJet()` 1151d8f25ad8SToby Isaac @*/ 11529371c9d4SSatish Balay PetscErrorCode PetscDTPTrimmedSize(PetscInt dim, PetscInt degree, PetscInt formDegree, PetscInt *size) { 1153d8f25ad8SToby Isaac PetscInt Nrk, Nbpt; // number of trimmed polynomials 1154d8f25ad8SToby Isaac 1155d8f25ad8SToby Isaac PetscFunctionBegin; 1156d8f25ad8SToby Isaac formDegree = PetscAbsInt(formDegree); 11579566063dSJacob Faibussowitsch PetscCall(PetscDTBinomialInt(degree + dim, degree + formDegree, &Nbpt)); 11589566063dSJacob Faibussowitsch PetscCall(PetscDTBinomialInt(degree + formDegree - 1, formDegree, &Nrk)); 1159d8f25ad8SToby Isaac Nbpt *= Nrk; 1160d8f25ad8SToby Isaac *size = Nbpt; 1161d8f25ad8SToby Isaac PetscFunctionReturn(0); 1162d8f25ad8SToby Isaac } 1163d8f25ad8SToby Isaac 1164d8f25ad8SToby Isaac /* there was a reference implementation based on section 4.4 of Arnold, Falk & Winther (acta numerica, 2006), but it 1165d8f25ad8SToby Isaac * was inferior to this implementation */ 11669371c9d4SSatish Balay static PetscErrorCode PetscDTPTrimmedEvalJet_Internal(PetscInt dim, PetscInt npoints, const PetscReal points[], PetscInt degree, PetscInt formDegree, PetscInt jetDegree, PetscReal p[]) { 1167d8f25ad8SToby Isaac PetscInt formDegreeOrig = formDegree; 1168d8f25ad8SToby Isaac PetscBool formNegative = (formDegreeOrig < 0) ? PETSC_TRUE : PETSC_FALSE; 1169d8f25ad8SToby Isaac 1170d8f25ad8SToby Isaac PetscFunctionBegin; 1171d8f25ad8SToby Isaac formDegree = PetscAbsInt(formDegreeOrig); 1172d8f25ad8SToby Isaac if (formDegree == 0) { 11739566063dSJacob Faibussowitsch PetscCall(PetscDTPKDEvalJet(dim, npoints, points, degree, jetDegree, p)); 1174d8f25ad8SToby Isaac PetscFunctionReturn(0); 1175d8f25ad8SToby Isaac } 1176d8f25ad8SToby Isaac if (formDegree == dim) { 11779566063dSJacob Faibussowitsch PetscCall(PetscDTPKDEvalJet(dim, npoints, points, degree - 1, jetDegree, p)); 1178d8f25ad8SToby Isaac PetscFunctionReturn(0); 1179d8f25ad8SToby Isaac } 1180d8f25ad8SToby Isaac PetscInt Nbpt; 11819566063dSJacob Faibussowitsch PetscCall(PetscDTPTrimmedSize(dim, degree, formDegree, &Nbpt)); 1182d8f25ad8SToby Isaac PetscInt Nf; 11839566063dSJacob Faibussowitsch PetscCall(PetscDTBinomialInt(dim, formDegree, &Nf)); 1184d8f25ad8SToby Isaac PetscInt Nk; 11859566063dSJacob Faibussowitsch PetscCall(PetscDTBinomialInt(dim + jetDegree, dim, &Nk)); 11869566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(p, Nbpt * Nf * Nk * npoints)); 1187d8f25ad8SToby Isaac 1188d8f25ad8SToby Isaac PetscInt Nbpm1; // number of scalar polynomials up to degree - 1; 11899566063dSJacob Faibussowitsch PetscCall(PetscDTBinomialInt(dim + degree - 1, dim, &Nbpm1)); 1190d8f25ad8SToby Isaac PetscReal *p_scalar; 11919566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(Nbpm1 * Nk * npoints, &p_scalar)); 11929566063dSJacob Faibussowitsch PetscCall(PetscDTPKDEvalJet(dim, npoints, points, degree - 1, jetDegree, p_scalar)); 1193d8f25ad8SToby Isaac PetscInt total = 0; 1194d8f25ad8SToby Isaac // First add the full polynomials up to degree - 1 into the basis: take the scalar 1195d8f25ad8SToby Isaac // and copy one for each form component 1196d8f25ad8SToby Isaac for (PetscInt i = 0; i < Nbpm1; i++) { 1197d8f25ad8SToby Isaac const PetscReal *src = &p_scalar[i * Nk * npoints]; 1198d8f25ad8SToby Isaac for (PetscInt f = 0; f < Nf; f++) { 1199d8f25ad8SToby Isaac PetscReal *dest = &p[(total++ * Nf + f) * Nk * npoints]; 12009566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(dest, src, Nk * npoints)); 1201d8f25ad8SToby Isaac } 1202d8f25ad8SToby Isaac } 1203d8f25ad8SToby Isaac PetscInt *form_atoms; 12049566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(formDegree + 1, &form_atoms)); 1205d8f25ad8SToby Isaac // construct the interior product pattern 1206d8f25ad8SToby Isaac PetscInt(*pattern)[3]; 1207d8f25ad8SToby Isaac PetscInt Nf1; // number of formDegree + 1 forms 12089566063dSJacob Faibussowitsch PetscCall(PetscDTBinomialInt(dim, formDegree + 1, &Nf1)); 1209d8f25ad8SToby Isaac PetscInt nnz = Nf1 * (formDegree + 1); 12109566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(Nf1 * (formDegree + 1), &pattern)); 12119566063dSJacob Faibussowitsch PetscCall(PetscDTAltVInteriorPattern(dim, formDegree + 1, pattern)); 1212d8f25ad8SToby Isaac PetscReal centroid = (1. - dim) / (dim + 1.); 1213d8f25ad8SToby Isaac PetscInt *deriv; 12149566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(dim, &deriv)); 1215d8f25ad8SToby Isaac for (PetscInt d = dim; d >= formDegree + 1; d--) { 1216d8f25ad8SToby Isaac PetscInt Nfd1; // number of formDegree + 1 forms in dimension d that include dx_0 1217d8f25ad8SToby Isaac // (equal to the number of formDegree forms in dimension d-1) 12189566063dSJacob Faibussowitsch PetscCall(PetscDTBinomialInt(d - 1, formDegree, &Nfd1)); 1219d8f25ad8SToby Isaac // The number of homogeneous (degree-1) scalar polynomials in d variables 1220d8f25ad8SToby Isaac PetscInt Nh; 12219566063dSJacob Faibussowitsch PetscCall(PetscDTBinomialInt(d - 1 + degree - 1, d - 1, &Nh)); 1222d8f25ad8SToby Isaac const PetscReal *h_scalar = &p_scalar[(Nbpm1 - Nh) * Nk * npoints]; 1223d8f25ad8SToby Isaac for (PetscInt b = 0; b < Nh; b++) { 1224d8f25ad8SToby Isaac const PetscReal *h_s = &h_scalar[b * Nk * npoints]; 1225d8f25ad8SToby Isaac for (PetscInt f = 0; f < Nfd1; f++) { 1226d8f25ad8SToby Isaac // construct all formDegree+1 forms that start with dx_(dim - d) /\ ... 1227d8f25ad8SToby Isaac form_atoms[0] = dim - d; 12289566063dSJacob Faibussowitsch PetscCall(PetscDTEnumSubset(d - 1, formDegree, f, &form_atoms[1])); 12299371c9d4SSatish Balay for (PetscInt i = 0; i < formDegree; i++) { form_atoms[1 + i] += form_atoms[0] + 1; } 1230d8f25ad8SToby Isaac PetscInt f_ind; // index of the resulting form 12319566063dSJacob Faibussowitsch PetscCall(PetscDTSubsetIndex(dim, formDegree + 1, form_atoms, &f_ind)); 1232d8f25ad8SToby Isaac PetscReal *p_f = &p[total++ * Nf * Nk * npoints]; 1233d8f25ad8SToby Isaac for (PetscInt nz = 0; nz < nnz; nz++) { 1234d8f25ad8SToby Isaac PetscInt i = pattern[nz][0]; // formDegree component 1235d8f25ad8SToby Isaac PetscInt j = pattern[nz][1]; // (formDegree + 1) component 1236d8f25ad8SToby Isaac PetscInt v = pattern[nz][2]; // coordinate component 1237d8f25ad8SToby Isaac PetscReal scale = v < 0 ? -1. : 1.; 1238d8f25ad8SToby Isaac 1239d8f25ad8SToby Isaac i = formNegative ? (Nf - 1 - i) : i; 1240d8f25ad8SToby Isaac scale = (formNegative && (i & 1)) ? -scale : scale; 1241d8f25ad8SToby Isaac v = v < 0 ? -(v + 1) : v; 12429371c9d4SSatish Balay if (j != f_ind) { continue; } 1243d8f25ad8SToby Isaac PetscReal *p_i = &p_f[i * Nk * npoints]; 1244d8f25ad8SToby Isaac for (PetscInt jet = 0; jet < Nk; jet++) { 1245d8f25ad8SToby Isaac const PetscReal *h_jet = &h_s[jet * npoints]; 1246d8f25ad8SToby Isaac PetscReal *p_jet = &p_i[jet * npoints]; 1247d8f25ad8SToby Isaac 12489371c9d4SSatish Balay for (PetscInt pt = 0; pt < npoints; pt++) { p_jet[pt] += scale * h_jet[pt] * (points[pt * dim + v] - centroid); } 12499566063dSJacob Faibussowitsch PetscCall(PetscDTIndexToGradedOrder(dim, jet, deriv)); 1250d8f25ad8SToby Isaac deriv[v]++; 1251d8f25ad8SToby Isaac PetscReal mult = deriv[v]; 1252d8f25ad8SToby Isaac PetscInt l; 12539566063dSJacob Faibussowitsch PetscCall(PetscDTGradedOrderToIndex(dim, deriv, &l)); 12549371c9d4SSatish Balay if (l >= Nk) { continue; } 1255d8f25ad8SToby Isaac p_jet = &p_i[l * npoints]; 12569371c9d4SSatish Balay for (PetscInt pt = 0; pt < npoints; pt++) { p_jet[pt] += scale * mult * h_jet[pt]; } 1257d8f25ad8SToby Isaac deriv[v]--; 1258d8f25ad8SToby Isaac } 1259d8f25ad8SToby Isaac } 1260d8f25ad8SToby Isaac } 1261d8f25ad8SToby Isaac } 1262d8f25ad8SToby Isaac } 126308401ef6SPierre Jolivet PetscCheck(total == Nbpt, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Incorrectly counted P trimmed polynomials"); 12649566063dSJacob Faibussowitsch PetscCall(PetscFree(deriv)); 12659566063dSJacob Faibussowitsch PetscCall(PetscFree(pattern)); 12669566063dSJacob Faibussowitsch PetscCall(PetscFree(form_atoms)); 12679566063dSJacob Faibussowitsch PetscCall(PetscFree(p_scalar)); 1268d8f25ad8SToby Isaac PetscFunctionReturn(0); 1269d8f25ad8SToby Isaac } 1270d8f25ad8SToby Isaac 1271d8f25ad8SToby Isaac /*@ 1272d8f25ad8SToby Isaac PetscDTPTrimmedEvalJet - Evaluate the jet (function and derivatives) of a basis of the trimmed polynomial k-forms up to 1273d8f25ad8SToby Isaac a given degree. 1274d8f25ad8SToby Isaac 1275d8f25ad8SToby Isaac Input Parameters: 1276d8f25ad8SToby Isaac + dim - the number of variables in the multivariate polynomials 1277d8f25ad8SToby Isaac . npoints - the number of points to evaluate the polynomials at 1278d8f25ad8SToby Isaac . points - [npoints x dim] array of point coordinates 1279d8f25ad8SToby Isaac . degree - the degree (sum of degrees on the variables in a monomial) of the trimmed polynomial space to evaluate. 1280d8f25ad8SToby Isaac There are ((dim + degree) choose (dim + formDegree)) x ((degree + formDegree - 1) choose (formDegree)) polynomials in this space. 1281d8f25ad8SToby Isaac (You can use PetscDTPTrimmedSize() to compute this size.) 1282d8f25ad8SToby Isaac . formDegree - the degree of the form 1283d8f25ad8SToby Isaac - jetDegree - the maximum order partial derivative to evaluate in the jet. There are ((dim + jetDegree) choose dim) partial derivatives 1284d8f25ad8SToby Isaac in the jet. Choosing jetDegree = 0 means to evaluate just the function and no derivatives 1285d8f25ad8SToby Isaac 12866aad120cSJose E. Roman Output Parameters: 1287d8f25ad8SToby Isaac - p - an array containing the evaluations of the PKD polynomials' jets on the points. The size is 1288d8f25ad8SToby Isaac PetscDTPTrimmedSize() x ((dim + formDegree) choose dim) x ((dim + k) choose dim) x npoints, 1289d8f25ad8SToby Isaac which also describes the order of the dimensions of this 1290d8f25ad8SToby Isaac four-dimensional array: 1291d8f25ad8SToby Isaac the first (slowest varying) dimension is basis function index; 1292d8f25ad8SToby Isaac the second dimension is component of the form; 1293d8f25ad8SToby Isaac the third dimension is jet index; 1294d8f25ad8SToby Isaac the fourth (fastest varying) dimension is the index of the evaluation point. 1295d8f25ad8SToby Isaac 1296d8f25ad8SToby Isaac Level: advanced 1297d8f25ad8SToby Isaac 1298d8f25ad8SToby Isaac Note: The ordering of the basis functions is not graded, so the basis functions are not nested by degree like PetscDTPKDEvalJet(). 1299d8f25ad8SToby Isaac The basis functions are not an L2-orthonormal basis on any particular domain. 1300d8f25ad8SToby Isaac 1301d8f25ad8SToby Isaac The implementation is based on the description of the trimmed polynomials up to degree r as 1302d8f25ad8SToby Isaac the direct sum of polynomials up to degree (r-1) and the Koszul differential applied to 1303d8f25ad8SToby Isaac homogeneous polynomials of degree (r-1). 1304d8f25ad8SToby Isaac 1305db781477SPatrick Sanan .seealso: `PetscDTPKDEvalJet()`, `PetscDTPTrimmedSize()` 1306d8f25ad8SToby Isaac @*/ 13079371c9d4SSatish Balay PetscErrorCode PetscDTPTrimmedEvalJet(PetscInt dim, PetscInt npoints, const PetscReal points[], PetscInt degree, PetscInt formDegree, PetscInt jetDegree, PetscReal p[]) { 1308d8f25ad8SToby Isaac PetscFunctionBegin; 13099566063dSJacob Faibussowitsch PetscCall(PetscDTPTrimmedEvalJet_Internal(dim, npoints, points, degree, formDegree, jetDegree, p)); 1310d8f25ad8SToby Isaac PetscFunctionReturn(0); 1311d8f25ad8SToby Isaac } 1312d8f25ad8SToby Isaac 1313e6a796c3SToby Isaac /* solve the symmetric tridiagonal eigenvalue system, writing the eigenvalues into eigs and the eigenvectors into V 1314e6a796c3SToby Isaac * with lds n; diag and subdiag are overwritten */ 13159371c9d4SSatish Balay static PetscErrorCode PetscDTSymmetricTridiagonalEigensolve(PetscInt n, PetscReal diag[], PetscReal subdiag[], PetscReal eigs[], PetscScalar V[]) { 1316e6a796c3SToby Isaac char jobz = 'V'; /* eigenvalues and eigenvectors */ 1317e6a796c3SToby Isaac char range = 'A'; /* all eigenvalues will be found */ 1318e6a796c3SToby Isaac PetscReal VL = 0.; /* ignored because range is 'A' */ 1319e6a796c3SToby Isaac PetscReal VU = 0.; /* ignored because range is 'A' */ 1320e6a796c3SToby Isaac PetscBLASInt IL = 0; /* ignored because range is 'A' */ 1321e6a796c3SToby Isaac PetscBLASInt IU = 0; /* ignored because range is 'A' */ 1322e6a796c3SToby Isaac PetscReal abstol = 0.; /* unused */ 1323e6a796c3SToby Isaac PetscBLASInt bn, bm, ldz; /* bm will equal bn on exit */ 1324e6a796c3SToby Isaac PetscBLASInt *isuppz; 1325e6a796c3SToby Isaac PetscBLASInt lwork, liwork; 1326e6a796c3SToby Isaac PetscReal workquery; 1327e6a796c3SToby Isaac PetscBLASInt iworkquery; 1328e6a796c3SToby Isaac PetscBLASInt *iwork; 1329e6a796c3SToby Isaac PetscBLASInt info; 1330e6a796c3SToby Isaac PetscReal *work = NULL; 1331e6a796c3SToby Isaac 1332e6a796c3SToby Isaac PetscFunctionBegin; 1333e6a796c3SToby Isaac #if !defined(PETSCDTGAUSSIANQUADRATURE_EIG) 1334e6a796c3SToby Isaac SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "A LAPACK symmetric tridiagonal eigensolver could not be found"); 1335e6a796c3SToby Isaac #endif 13369566063dSJacob Faibussowitsch PetscCall(PetscBLASIntCast(n, &bn)); 13379566063dSJacob Faibussowitsch PetscCall(PetscBLASIntCast(n, &ldz)); 1338e6a796c3SToby Isaac #if !defined(PETSC_MISSING_LAPACK_STEGR) 13399566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(2 * n, &isuppz)); 1340e6a796c3SToby Isaac lwork = -1; 1341e6a796c3SToby Isaac liwork = -1; 1342792fecdfSBarry Smith PetscCallBLAS("LAPACKstegr", LAPACKstegr_(&jobz, &range, &bn, diag, subdiag, &VL, &VU, &IL, &IU, &abstol, &bm, eigs, V, &ldz, isuppz, &workquery, &lwork, &iworkquery, &liwork, &info)); 134328b400f6SJacob Faibussowitsch PetscCheck(!info, PETSC_COMM_SELF, PETSC_ERR_PLIB, "xSTEGR error"); 1344e6a796c3SToby Isaac lwork = (PetscBLASInt)workquery; 1345e6a796c3SToby Isaac liwork = (PetscBLASInt)iworkquery; 13469566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(lwork, &work, liwork, &iwork)); 13479566063dSJacob Faibussowitsch PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF)); 1348792fecdfSBarry Smith PetscCallBLAS("LAPACKstegr", LAPACKstegr_(&jobz, &range, &bn, diag, subdiag, &VL, &VU, &IL, &IU, &abstol, &bm, eigs, V, &ldz, isuppz, work, &lwork, iwork, &liwork, &info)); 13499566063dSJacob Faibussowitsch PetscCall(PetscFPTrapPop()); 135028b400f6SJacob Faibussowitsch PetscCheck(!info, PETSC_COMM_SELF, PETSC_ERR_PLIB, "xSTEGR error"); 13519566063dSJacob Faibussowitsch PetscCall(PetscFree2(work, iwork)); 13529566063dSJacob Faibussowitsch PetscCall(PetscFree(isuppz)); 1353e6a796c3SToby Isaac #elif !defined(PETSC_MISSING_LAPACK_STEQR) 1354e6a796c3SToby Isaac jobz = 'I'; /* Compute eigenvalues and eigenvectors of the 1355e6a796c3SToby Isaac tridiagonal matrix. Z is initialized to the identity 1356e6a796c3SToby Isaac matrix. */ 13579566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(PetscMax(1, 2 * n - 2), &work)); 1358792fecdfSBarry Smith PetscCallBLAS("LAPACKsteqr", LAPACKsteqr_("I", &bn, diag, subdiag, V, &ldz, work, &info)); 13599566063dSJacob Faibussowitsch PetscCall(PetscFPTrapPop()); 136028b400f6SJacob Faibussowitsch PetscCheck(!info, PETSC_COMM_SELF, PETSC_ERR_PLIB, "xSTEQR error"); 13619566063dSJacob Faibussowitsch PetscCall(PetscFree(work)); 13629566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(eigs, diag, n)); 1363e6a796c3SToby Isaac #endif 1364e6a796c3SToby Isaac PetscFunctionReturn(0); 1365e6a796c3SToby Isaac } 1366e6a796c3SToby Isaac 1367e6a796c3SToby Isaac /* Formula for the weights at the endpoints (-1 and 1) of Gauss-Lobatto-Jacobi 1368e6a796c3SToby Isaac * quadrature rules on the interval [-1, 1] */ 13699371c9d4SSatish Balay static PetscErrorCode PetscDTGaussLobattoJacobiEndweights_Internal(PetscInt n, PetscReal alpha, PetscReal beta, PetscReal *leftw, PetscReal *rightw) { 1370e6a796c3SToby Isaac PetscReal twoab1; 1371e6a796c3SToby Isaac PetscInt m = n - 2; 1372e6a796c3SToby Isaac PetscReal a = alpha + 1.; 1373e6a796c3SToby Isaac PetscReal b = beta + 1.; 1374e6a796c3SToby Isaac PetscReal gra, grb; 1375e6a796c3SToby Isaac 1376e6a796c3SToby Isaac PetscFunctionBegin; 1377e6a796c3SToby Isaac twoab1 = PetscPowReal(2., a + b - 1.); 1378e6a796c3SToby Isaac #if defined(PETSC_HAVE_LGAMMA) 13799371c9d4SSatish Balay grb = PetscExpReal(2. * PetscLGamma(b + 1.) + PetscLGamma(m + 1.) + PetscLGamma(m + a + 1.) - (PetscLGamma(m + b + 1) + PetscLGamma(m + a + b + 1.))); 13809371c9d4SSatish Balay gra = PetscExpReal(2. * PetscLGamma(a + 1.) + PetscLGamma(m + 1.) + PetscLGamma(m + b + 1.) - (PetscLGamma(m + a + 1) + PetscLGamma(m + a + b + 1.))); 1381e6a796c3SToby Isaac #else 1382e6a796c3SToby Isaac { 1383e6a796c3SToby Isaac PetscInt alphai = (PetscInt)alpha; 1384e6a796c3SToby Isaac PetscInt betai = (PetscInt)beta; 1385e6a796c3SToby Isaac 1386e6a796c3SToby Isaac if ((PetscReal)alphai == alpha && (PetscReal)betai == beta) { 1387e6a796c3SToby Isaac PetscReal binom1, binom2; 1388e6a796c3SToby Isaac 13899566063dSJacob Faibussowitsch PetscCall(PetscDTBinomial(m + b, b, &binom1)); 13909566063dSJacob Faibussowitsch PetscCall(PetscDTBinomial(m + a + b, b, &binom2)); 1391e6a796c3SToby Isaac grb = 1. / (binom1 * binom2); 13929566063dSJacob Faibussowitsch PetscCall(PetscDTBinomial(m + a, a, &binom1)); 13939566063dSJacob Faibussowitsch PetscCall(PetscDTBinomial(m + a + b, a, &binom2)); 1394e6a796c3SToby Isaac gra = 1. / (binom1 * binom2); 1395e6a796c3SToby Isaac } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "lgamma() - math routine is unavailable."); 1396e6a796c3SToby Isaac } 1397e6a796c3SToby Isaac #endif 1398e6a796c3SToby Isaac *leftw = twoab1 * grb / b; 1399e6a796c3SToby Isaac *rightw = twoab1 * gra / a; 1400e6a796c3SToby Isaac PetscFunctionReturn(0); 1401e6a796c3SToby Isaac } 1402e6a796c3SToby Isaac 1403e6a796c3SToby Isaac /* Evaluates the nth jacobi polynomial with weight parameters a,b at a point x. 1404e6a796c3SToby Isaac Recurrence relations implemented from the pseudocode given in Karniadakis and Sherwin, Appendix B */ 14059371c9d4SSatish Balay static inline PetscErrorCode PetscDTComputeJacobi(PetscReal a, PetscReal b, PetscInt n, PetscReal x, PetscReal *P) { 140694e21283SToby Isaac PetscReal pn1, pn2; 140794e21283SToby Isaac PetscReal cnm1, cnm1x, cnm2; 1408e6a796c3SToby Isaac PetscInt k; 1409e6a796c3SToby Isaac 1410e6a796c3SToby Isaac PetscFunctionBegin; 14119371c9d4SSatish Balay if (!n) { 14129371c9d4SSatish Balay *P = 1.0; 14139371c9d4SSatish Balay PetscFunctionReturn(0); 14149371c9d4SSatish Balay } 141594e21283SToby Isaac PetscDTJacobiRecurrence_Internal(1, a, b, cnm1, cnm1x, cnm2); 141694e21283SToby Isaac pn2 = 1.; 141794e21283SToby Isaac pn1 = cnm1 + cnm1x * x; 14189371c9d4SSatish Balay if (n == 1) { 14199371c9d4SSatish Balay *P = pn1; 14209371c9d4SSatish Balay PetscFunctionReturn(0); 14219371c9d4SSatish Balay } 1422e6a796c3SToby Isaac *P = 0.0; 1423e6a796c3SToby Isaac for (k = 2; k < n + 1; ++k) { 142494e21283SToby Isaac PetscDTJacobiRecurrence_Internal(k, a, b, cnm1, cnm1x, cnm2); 1425e6a796c3SToby Isaac 142694e21283SToby Isaac *P = (cnm1 + cnm1x * x) * pn1 - cnm2 * pn2; 1427e6a796c3SToby Isaac pn2 = pn1; 1428e6a796c3SToby Isaac pn1 = *P; 1429e6a796c3SToby Isaac } 1430e6a796c3SToby Isaac PetscFunctionReturn(0); 1431e6a796c3SToby Isaac } 1432e6a796c3SToby Isaac 1433e6a796c3SToby Isaac /* Evaluates the first derivative of P_{n}^{a,b} at a point x. */ 14349371c9d4SSatish Balay static inline PetscErrorCode PetscDTComputeJacobiDerivative(PetscReal a, PetscReal b, PetscInt n, PetscReal x, PetscInt k, PetscReal *P) { 1435e6a796c3SToby Isaac PetscReal nP; 1436e6a796c3SToby Isaac PetscInt i; 1437e6a796c3SToby Isaac 1438e6a796c3SToby Isaac PetscFunctionBegin; 143917a42bb7SSatish Balay *P = 0.0; 144017a42bb7SSatish Balay if (k > n) PetscFunctionReturn(0); 14419566063dSJacob Faibussowitsch PetscCall(PetscDTComputeJacobi(a + k, b + k, n - k, x, &nP)); 1442e6a796c3SToby Isaac for (i = 0; i < k; i++) nP *= (a + b + n + 1. + i) * 0.5; 1443e6a796c3SToby Isaac *P = nP; 1444e6a796c3SToby Isaac PetscFunctionReturn(0); 1445e6a796c3SToby Isaac } 1446e6a796c3SToby Isaac 14479371c9d4SSatish Balay static PetscErrorCode PetscDTGaussJacobiQuadrature_Newton_Internal(PetscInt npoints, PetscReal a, PetscReal b, PetscReal x[], PetscReal w[]) { 1448e6a796c3SToby Isaac PetscInt maxIter = 100; 144994e21283SToby Isaac PetscReal eps = PetscExpReal(0.75 * PetscLogReal(PETSC_MACHINE_EPSILON)); 1450200b5abcSJed Brown PetscReal a1, a6, gf; 1451e6a796c3SToby Isaac PetscInt k; 1452e6a796c3SToby Isaac 1453e6a796c3SToby Isaac PetscFunctionBegin; 1454e6a796c3SToby Isaac 1455e6a796c3SToby Isaac a1 = PetscPowReal(2.0, a + b + 1); 145694e21283SToby Isaac #if defined(PETSC_HAVE_LGAMMA) 1457200b5abcSJed Brown { 1458200b5abcSJed Brown PetscReal a2, a3, a4, a5; 145994e21283SToby Isaac a2 = PetscLGamma(a + npoints + 1); 146094e21283SToby Isaac a3 = PetscLGamma(b + npoints + 1); 146194e21283SToby Isaac a4 = PetscLGamma(a + b + npoints + 1); 146294e21283SToby Isaac a5 = PetscLGamma(npoints + 1); 146394e21283SToby Isaac gf = PetscExpReal(a2 + a3 - (a4 + a5)); 1464200b5abcSJed Brown } 1465e6a796c3SToby Isaac #else 1466e6a796c3SToby Isaac { 1467e6a796c3SToby Isaac PetscInt ia, ib; 1468e6a796c3SToby Isaac 1469e6a796c3SToby Isaac ia = (PetscInt)a; 1470e6a796c3SToby Isaac ib = (PetscInt)b; 147194e21283SToby Isaac gf = 1.; 147294e21283SToby Isaac if (ia == a && ia >= 0) { /* compute ratio of rising factorals wrt a */ 147394e21283SToby Isaac for (k = 0; k < ia; k++) gf *= (npoints + 1. + k) / (npoints + b + 1. + k); 147494e21283SToby Isaac } else if (b == b && ib >= 0) { /* compute ratio of rising factorials wrt b */ 147594e21283SToby Isaac for (k = 0; k < ib; k++) gf *= (npoints + 1. + k) / (npoints + a + 1. + k); 147694e21283SToby Isaac } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "lgamma() - math routine is unavailable."); 1477e6a796c3SToby Isaac } 1478e6a796c3SToby Isaac #endif 1479e6a796c3SToby Isaac 148094e21283SToby Isaac a6 = a1 * gf; 1481e6a796c3SToby Isaac /* Computes the m roots of P_{m}^{a,b} on [-1,1] by Newton's method with Chebyshev points as initial guesses. 1482e6a796c3SToby Isaac Algorithm implemented from the pseudocode given by Karniadakis and Sherwin and Python in FIAT */ 1483e6a796c3SToby Isaac for (k = 0; k < npoints; ++k) { 148494e21283SToby Isaac PetscReal r = PetscCosReal(PETSC_PI * (1. - (4. * k + 3. + 2. * b) / (4. * npoints + 2. * (a + b + 1.)))), dP; 1485e6a796c3SToby Isaac PetscInt j; 1486e6a796c3SToby Isaac 1487e6a796c3SToby Isaac if (k > 0) r = 0.5 * (r + x[k - 1]); 1488e6a796c3SToby Isaac for (j = 0; j < maxIter; ++j) { 1489e6a796c3SToby Isaac PetscReal s = 0.0, delta, f, fp; 1490e6a796c3SToby Isaac PetscInt i; 1491e6a796c3SToby Isaac 1492e6a796c3SToby Isaac for (i = 0; i < k; ++i) s = s + 1.0 / (r - x[i]); 14939566063dSJacob Faibussowitsch PetscCall(PetscDTComputeJacobi(a, b, npoints, r, &f)); 14949566063dSJacob Faibussowitsch PetscCall(PetscDTComputeJacobiDerivative(a, b, npoints, r, 1, &fp)); 1495e6a796c3SToby Isaac delta = f / (fp - f * s); 1496e6a796c3SToby Isaac r = r - delta; 1497e6a796c3SToby Isaac if (PetscAbsReal(delta) < eps) break; 1498e6a796c3SToby Isaac } 1499e6a796c3SToby Isaac x[k] = r; 15009566063dSJacob Faibussowitsch PetscCall(PetscDTComputeJacobiDerivative(a, b, npoints, x[k], 1, &dP)); 1501e6a796c3SToby Isaac w[k] = a6 / (1.0 - PetscSqr(x[k])) / PetscSqr(dP); 1502e6a796c3SToby Isaac } 1503e6a796c3SToby Isaac PetscFunctionReturn(0); 1504e6a796c3SToby Isaac } 1505e6a796c3SToby Isaac 150694e21283SToby Isaac /* Compute the diagonals of the Jacobi matrix used in Golub & Welsch algorithms for Gauss-Jacobi 1507e6a796c3SToby Isaac * quadrature weight calculations on [-1,1] for exponents (1. + x)^a (1.-x)^b */ 15089371c9d4SSatish Balay static PetscErrorCode PetscDTJacobiMatrix_Internal(PetscInt nPoints, PetscReal a, PetscReal b, PetscReal *d, PetscReal *s) { 1509e6a796c3SToby Isaac PetscInt i; 1510e6a796c3SToby Isaac 1511e6a796c3SToby Isaac PetscFunctionBegin; 1512e6a796c3SToby Isaac for (i = 0; i < nPoints; i++) { 151394e21283SToby Isaac PetscReal A, B, C; 1514e6a796c3SToby Isaac 151594e21283SToby Isaac PetscDTJacobiRecurrence_Internal(i + 1, a, b, A, B, C); 151694e21283SToby Isaac d[i] = -A / B; 151794e21283SToby Isaac if (i) s[i - 1] *= C / B; 151894e21283SToby Isaac if (i < nPoints - 1) s[i] = 1. / B; 1519e6a796c3SToby Isaac } 1520e6a796c3SToby Isaac PetscFunctionReturn(0); 1521e6a796c3SToby Isaac } 1522e6a796c3SToby Isaac 15239371c9d4SSatish Balay static PetscErrorCode PetscDTGaussJacobiQuadrature_GolubWelsch_Internal(PetscInt npoints, PetscReal a, PetscReal b, PetscReal *x, PetscReal *w) { 1524e6a796c3SToby Isaac PetscReal mu0; 1525e6a796c3SToby Isaac PetscReal ga, gb, gab; 1526e6a796c3SToby Isaac PetscInt i; 1527e6a796c3SToby Isaac 1528e6a796c3SToby Isaac PetscFunctionBegin; 15299566063dSJacob Faibussowitsch PetscCall(PetscCitationsRegister(GolubWelschCitation, &GolubWelschCite)); 1530e6a796c3SToby Isaac 1531e6a796c3SToby Isaac #if defined(PETSC_HAVE_TGAMMA) 1532e6a796c3SToby Isaac ga = PetscTGamma(a + 1); 1533e6a796c3SToby Isaac gb = PetscTGamma(b + 1); 1534e6a796c3SToby Isaac gab = PetscTGamma(a + b + 2); 1535e6a796c3SToby Isaac #else 1536e6a796c3SToby Isaac { 1537e6a796c3SToby Isaac PetscInt ia, ib; 1538e6a796c3SToby Isaac 1539e6a796c3SToby Isaac ia = (PetscInt)a; 1540e6a796c3SToby Isaac ib = (PetscInt)b; 1541e6a796c3SToby Isaac if (ia == a && ib == b && ia + 1 > 0 && ib + 1 > 0 && ia + ib + 2 > 0) { /* All gamma(x) terms are (x-1)! terms */ 15429566063dSJacob Faibussowitsch PetscCall(PetscDTFactorial(ia, &ga)); 15439566063dSJacob Faibussowitsch PetscCall(PetscDTFactorial(ib, &gb)); 15449566063dSJacob Faibussowitsch PetscCall(PetscDTFactorial(ia + ib + 1, &gb)); 1545e6a796c3SToby Isaac } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "tgamma() - math routine is unavailable."); 1546e6a796c3SToby Isaac } 1547e6a796c3SToby Isaac #endif 1548e6a796c3SToby Isaac mu0 = PetscPowReal(2., a + b + 1.) * ga * gb / gab; 1549e6a796c3SToby Isaac 1550e6a796c3SToby Isaac #if defined(PETSCDTGAUSSIANQUADRATURE_EIG) 1551e6a796c3SToby Isaac { 1552e6a796c3SToby Isaac PetscReal *diag, *subdiag; 1553e6a796c3SToby Isaac PetscScalar *V; 1554e6a796c3SToby Isaac 15559566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(npoints, &diag, npoints, &subdiag)); 15569566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(npoints * npoints, &V)); 15579566063dSJacob Faibussowitsch PetscCall(PetscDTJacobiMatrix_Internal(npoints, a, b, diag, subdiag)); 1558e6a796c3SToby Isaac for (i = 0; i < npoints - 1; i++) subdiag[i] = PetscSqrtReal(subdiag[i]); 15599566063dSJacob Faibussowitsch PetscCall(PetscDTSymmetricTridiagonalEigensolve(npoints, diag, subdiag, x, V)); 156094e21283SToby Isaac for (i = 0; i < npoints; i++) w[i] = PetscSqr(PetscRealPart(V[i * npoints])) * mu0; 15619566063dSJacob Faibussowitsch PetscCall(PetscFree(V)); 15629566063dSJacob Faibussowitsch PetscCall(PetscFree2(diag, subdiag)); 1563e6a796c3SToby Isaac } 1564e6a796c3SToby Isaac #else 1565e6a796c3SToby Isaac SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "A LAPACK symmetric tridiagonal eigensolver could not be found"); 1566e6a796c3SToby Isaac #endif 156794e21283SToby Isaac { /* As of March 2, 2020, The Sun Performance Library breaks the LAPACK contract for xstegr and xsteqr: the 156894e21283SToby Isaac eigenvalues are not guaranteed to be in ascending order. So we heave a passive aggressive sigh and check that 156994e21283SToby Isaac the eigenvalues are sorted */ 157094e21283SToby Isaac PetscBool sorted; 157194e21283SToby Isaac 15729566063dSJacob Faibussowitsch PetscCall(PetscSortedReal(npoints, x, &sorted)); 157394e21283SToby Isaac if (!sorted) { 157494e21283SToby Isaac PetscInt *order, i; 157594e21283SToby Isaac PetscReal *tmp; 157694e21283SToby Isaac 15779566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(npoints, &order, npoints, &tmp)); 157894e21283SToby Isaac for (i = 0; i < npoints; i++) order[i] = i; 15799566063dSJacob Faibussowitsch PetscCall(PetscSortRealWithPermutation(npoints, x, order)); 15809566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(tmp, x, npoints)); 158194e21283SToby Isaac for (i = 0; i < npoints; i++) x[i] = tmp[order[i]]; 15829566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(tmp, w, npoints)); 158394e21283SToby Isaac for (i = 0; i < npoints; i++) w[i] = tmp[order[i]]; 15849566063dSJacob Faibussowitsch PetscCall(PetscFree2(order, tmp)); 158594e21283SToby Isaac } 158694e21283SToby Isaac } 1587e6a796c3SToby Isaac PetscFunctionReturn(0); 1588e6a796c3SToby Isaac } 1589e6a796c3SToby Isaac 15909371c9d4SSatish Balay static PetscErrorCode PetscDTGaussJacobiQuadrature_Internal(PetscInt npoints, PetscReal alpha, PetscReal beta, PetscReal x[], PetscReal w[], PetscBool newton) { 1591e6a796c3SToby Isaac PetscFunctionBegin; 159208401ef6SPierre Jolivet PetscCheck(npoints >= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of points must be positive"); 1593e6a796c3SToby Isaac /* If asking for a 1D Lobatto point, just return the non-Lobatto 1D point */ 159408401ef6SPierre Jolivet PetscCheck(alpha > -1., PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "alpha must be > -1."); 159508401ef6SPierre Jolivet PetscCheck(beta > -1., PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "beta must be > -1."); 1596e6a796c3SToby Isaac 15971baa6e33SBarry Smith if (newton) PetscCall(PetscDTGaussJacobiQuadrature_Newton_Internal(npoints, alpha, beta, x, w)); 15981baa6e33SBarry Smith else PetscCall(PetscDTGaussJacobiQuadrature_GolubWelsch_Internal(npoints, alpha, beta, x, w)); 1599e6a796c3SToby Isaac if (alpha == beta) { /* symmetrize */ 1600e6a796c3SToby Isaac PetscInt i; 1601e6a796c3SToby Isaac for (i = 0; i < (npoints + 1) / 2; i++) { 1602e6a796c3SToby Isaac PetscInt j = npoints - 1 - i; 1603e6a796c3SToby Isaac PetscReal xi = x[i]; 1604e6a796c3SToby Isaac PetscReal xj = x[j]; 1605e6a796c3SToby Isaac PetscReal wi = w[i]; 1606e6a796c3SToby Isaac PetscReal wj = w[j]; 1607e6a796c3SToby Isaac 1608e6a796c3SToby Isaac x[i] = (xi - xj) / 2.; 1609e6a796c3SToby Isaac x[j] = (xj - xi) / 2.; 1610e6a796c3SToby Isaac w[i] = w[j] = (wi + wj) / 2.; 1611e6a796c3SToby Isaac } 1612e6a796c3SToby Isaac } 1613e6a796c3SToby Isaac PetscFunctionReturn(0); 1614e6a796c3SToby Isaac } 1615e6a796c3SToby Isaac 161694e21283SToby Isaac /*@ 161794e21283SToby Isaac PetscDTGaussJacobiQuadrature - quadrature for the interval [a, b] with the weight function 161894e21283SToby Isaac $(x-a)^\alpha (x-b)^\beta$. 161994e21283SToby Isaac 162094e21283SToby Isaac Not collective 162194e21283SToby Isaac 162294e21283SToby Isaac Input Parameters: 162394e21283SToby Isaac + npoints - the number of points in the quadrature rule 162494e21283SToby Isaac . a - the left endpoint of the interval 162594e21283SToby Isaac . b - the right endpoint of the interval 162694e21283SToby Isaac . alpha - the left exponent 162794e21283SToby Isaac - beta - the right exponent 162894e21283SToby Isaac 162994e21283SToby Isaac Output Parameters: 163094e21283SToby Isaac + x - array of length npoints, the locations of the quadrature points 163194e21283SToby Isaac - w - array of length npoints, the weights of the quadrature points 163294e21283SToby Isaac 163394e21283SToby Isaac Level: intermediate 163494e21283SToby Isaac 163594e21283SToby Isaac Note: this quadrature rule is exact for polynomials up to degree 2*npoints - 1. 163694e21283SToby Isaac @*/ 16379371c9d4SSatish Balay PetscErrorCode PetscDTGaussJacobiQuadrature(PetscInt npoints, PetscReal a, PetscReal b, PetscReal alpha, PetscReal beta, PetscReal x[], PetscReal w[]) { 163894e21283SToby Isaac PetscInt i; 1639e6a796c3SToby Isaac 1640e6a796c3SToby Isaac PetscFunctionBegin; 16419566063dSJacob Faibussowitsch PetscCall(PetscDTGaussJacobiQuadrature_Internal(npoints, alpha, beta, x, w, PetscDTGaussQuadratureNewton_Internal)); 164294e21283SToby Isaac if (a != -1. || b != 1.) { /* shift */ 164394e21283SToby Isaac for (i = 0; i < npoints; i++) { 164494e21283SToby Isaac x[i] = (x[i] + 1.) * ((b - a) / 2.) + a; 164594e21283SToby Isaac w[i] *= (b - a) / 2.; 164694e21283SToby Isaac } 164794e21283SToby Isaac } 1648e6a796c3SToby Isaac PetscFunctionReturn(0); 1649e6a796c3SToby Isaac } 1650e6a796c3SToby Isaac 16519371c9d4SSatish Balay static PetscErrorCode PetscDTGaussLobattoJacobiQuadrature_Internal(PetscInt npoints, PetscReal alpha, PetscReal beta, PetscReal x[], PetscReal w[], PetscBool newton) { 1652e6a796c3SToby Isaac PetscInt i; 1653e6a796c3SToby Isaac 1654e6a796c3SToby Isaac PetscFunctionBegin; 165508401ef6SPierre Jolivet PetscCheck(npoints >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of points must be positive"); 1656e6a796c3SToby Isaac /* If asking for a 1D Lobatto point, just return the non-Lobatto 1D point */ 165708401ef6SPierre Jolivet PetscCheck(alpha > -1., PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "alpha must be > -1."); 165808401ef6SPierre Jolivet PetscCheck(beta > -1., PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "beta must be > -1."); 1659e6a796c3SToby Isaac 1660e6a796c3SToby Isaac x[0] = -1.; 1661e6a796c3SToby Isaac x[npoints - 1] = 1.; 1662*48a46eb9SPierre Jolivet if (npoints > 2) PetscCall(PetscDTGaussJacobiQuadrature_Internal(npoints - 2, alpha + 1., beta + 1., &x[1], &w[1], newton)); 16639371c9d4SSatish Balay for (i = 1; i < npoints - 1; i++) { w[i] /= (1. - x[i] * x[i]); } 16649566063dSJacob Faibussowitsch PetscCall(PetscDTGaussLobattoJacobiEndweights_Internal(npoints, alpha, beta, &w[0], &w[npoints - 1])); 1665e6a796c3SToby Isaac PetscFunctionReturn(0); 1666e6a796c3SToby Isaac } 1667e6a796c3SToby Isaac 166837045ce4SJed Brown /*@ 166994e21283SToby Isaac PetscDTGaussLobattoJacobiQuadrature - quadrature for the interval [a, b] with the weight function 167094e21283SToby Isaac $(x-a)^\alpha (x-b)^\beta$, with endpoints a and b included as quadrature points. 167194e21283SToby Isaac 167294e21283SToby Isaac Not collective 167394e21283SToby Isaac 167494e21283SToby Isaac Input Parameters: 167594e21283SToby Isaac + npoints - the number of points in the quadrature rule 167694e21283SToby Isaac . a - the left endpoint of the interval 167794e21283SToby Isaac . b - the right endpoint of the interval 167894e21283SToby Isaac . alpha - the left exponent 167994e21283SToby Isaac - beta - the right exponent 168094e21283SToby Isaac 168194e21283SToby Isaac Output Parameters: 168294e21283SToby Isaac + x - array of length npoints, the locations of the quadrature points 168394e21283SToby Isaac - w - array of length npoints, the weights of the quadrature points 168494e21283SToby Isaac 168594e21283SToby Isaac Level: intermediate 168694e21283SToby Isaac 168794e21283SToby Isaac Note: this quadrature rule is exact for polynomials up to degree 2*npoints - 3. 168894e21283SToby Isaac @*/ 16899371c9d4SSatish Balay PetscErrorCode PetscDTGaussLobattoJacobiQuadrature(PetscInt npoints, PetscReal a, PetscReal b, PetscReal alpha, PetscReal beta, PetscReal x[], PetscReal w[]) { 169094e21283SToby Isaac PetscInt i; 169194e21283SToby Isaac 169294e21283SToby Isaac PetscFunctionBegin; 16939566063dSJacob Faibussowitsch PetscCall(PetscDTGaussLobattoJacobiQuadrature_Internal(npoints, alpha, beta, x, w, PetscDTGaussQuadratureNewton_Internal)); 169494e21283SToby Isaac if (a != -1. || b != 1.) { /* shift */ 169594e21283SToby Isaac for (i = 0; i < npoints; i++) { 169694e21283SToby Isaac x[i] = (x[i] + 1.) * ((b - a) / 2.) + a; 169794e21283SToby Isaac w[i] *= (b - a) / 2.; 169894e21283SToby Isaac } 169994e21283SToby Isaac } 170094e21283SToby Isaac PetscFunctionReturn(0); 170194e21283SToby Isaac } 170294e21283SToby Isaac 170394e21283SToby Isaac /*@ 1704e6a796c3SToby Isaac PetscDTGaussQuadrature - create Gauss-Legendre quadrature 170537045ce4SJed Brown 170637045ce4SJed Brown Not Collective 170737045ce4SJed Brown 17084165533cSJose E. Roman Input Parameters: 170937045ce4SJed Brown + npoints - number of points 171037045ce4SJed Brown . a - left end of interval (often-1) 171137045ce4SJed Brown - b - right end of interval (often +1) 171237045ce4SJed Brown 17134165533cSJose E. Roman Output Parameters: 171437045ce4SJed Brown + x - quadrature points 171537045ce4SJed Brown - w - quadrature weights 171637045ce4SJed Brown 171737045ce4SJed Brown Level: intermediate 171837045ce4SJed Brown 171937045ce4SJed Brown References: 1720606c0280SSatish Balay . * - Golub and Welsch, Calculation of Quadrature Rules, Math. Comp. 23(106), 1969. 172137045ce4SJed Brown 1722db781477SPatrick Sanan .seealso: `PetscDTLegendreEval()` 172337045ce4SJed Brown @*/ 17249371c9d4SSatish Balay PetscErrorCode PetscDTGaussQuadrature(PetscInt npoints, PetscReal a, PetscReal b, PetscReal *x, PetscReal *w) { 172537045ce4SJed Brown PetscInt i; 172637045ce4SJed Brown 172737045ce4SJed Brown PetscFunctionBegin; 17289566063dSJacob Faibussowitsch PetscCall(PetscDTGaussJacobiQuadrature_Internal(npoints, 0., 0., x, w, PetscDTGaussQuadratureNewton_Internal)); 172994e21283SToby Isaac if (a != -1. || b != 1.) { /* shift */ 173037045ce4SJed Brown for (i = 0; i < npoints; i++) { 1731e6a796c3SToby Isaac x[i] = (x[i] + 1.) * ((b - a) / 2.) + a; 1732e6a796c3SToby Isaac w[i] *= (b - a) / 2.; 173337045ce4SJed Brown } 173437045ce4SJed Brown } 173537045ce4SJed Brown PetscFunctionReturn(0); 173637045ce4SJed Brown } 1737194825f6SJed Brown 17388272889dSSatish Balay /*@C 17398272889dSSatish Balay PetscDTGaussLobattoLegendreQuadrature - creates a set of the locations and weights of the Gauss-Lobatto-Legendre 17408272889dSSatish Balay nodes of a given size on the domain [-1,1] 17418272889dSSatish Balay 17428272889dSSatish Balay Not Collective 17438272889dSSatish Balay 1744d8d19677SJose E. Roman Input Parameters: 17458272889dSSatish Balay + n - number of grid nodes 1746f2e8fe4dShannah_mairs - type - PETSCGAUSSLOBATTOLEGENDRE_VIA_LINEAR_ALGEBRA or PETSCGAUSSLOBATTOLEGENDRE_VIA_NEWTON 17478272889dSSatish Balay 17484165533cSJose E. Roman Output Parameters: 17498272889dSSatish Balay + x - quadrature points 17508272889dSSatish Balay - w - quadrature weights 17518272889dSSatish Balay 17528272889dSSatish Balay Notes: 17538272889dSSatish Balay For n > 30 the Newton approach computes duplicate (incorrect) values for some nodes because the initial guess is apparently not 17548272889dSSatish Balay close enough to the desired solution 17558272889dSSatish Balay 17568272889dSSatish Balay These are useful for implementing spectral methods based on Gauss-Lobatto-Legendre (GLL) nodes 17578272889dSSatish Balay 1758a8d69d7bSBarry 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 17598272889dSSatish Balay 17608272889dSSatish Balay Level: intermediate 17618272889dSSatish Balay 1762db781477SPatrick Sanan .seealso: `PetscDTGaussQuadrature()` 17638272889dSSatish Balay 17648272889dSSatish Balay @*/ 17659371c9d4SSatish Balay PetscErrorCode PetscDTGaussLobattoLegendreQuadrature(PetscInt npoints, PetscGaussLobattoLegendreCreateType type, PetscReal *x, PetscReal *w) { 1766e6a796c3SToby Isaac PetscBool newton; 17678272889dSSatish Balay 17688272889dSSatish Balay PetscFunctionBegin; 176908401ef6SPierre Jolivet PetscCheck(npoints >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must provide at least 2 grid points per element"); 177094e21283SToby Isaac newton = (PetscBool)(type == PETSCGAUSSLOBATTOLEGENDRE_VIA_NEWTON); 17719566063dSJacob Faibussowitsch PetscCall(PetscDTGaussLobattoJacobiQuadrature_Internal(npoints, 0., 0., x, w, newton)); 17728272889dSSatish Balay PetscFunctionReturn(0); 17738272889dSSatish Balay } 17748272889dSSatish Balay 1775744bafbcSMatthew G. Knepley /*@ 1776744bafbcSMatthew G. Knepley PetscDTGaussTensorQuadrature - creates a tensor-product Gauss quadrature 1777744bafbcSMatthew G. Knepley 1778744bafbcSMatthew G. Knepley Not Collective 1779744bafbcSMatthew G. Knepley 17804165533cSJose E. Roman Input Parameters: 1781744bafbcSMatthew G. Knepley + dim - The spatial dimension 1782a6b92713SMatthew G. Knepley . Nc - The number of components 1783744bafbcSMatthew G. Knepley . npoints - number of points in one dimension 1784744bafbcSMatthew G. Knepley . a - left end of interval (often-1) 1785744bafbcSMatthew G. Knepley - b - right end of interval (often +1) 1786744bafbcSMatthew G. Knepley 17874165533cSJose E. Roman Output Parameter: 1788744bafbcSMatthew G. Knepley . q - A PetscQuadrature object 1789744bafbcSMatthew G. Knepley 1790744bafbcSMatthew G. Knepley Level: intermediate 1791744bafbcSMatthew G. Knepley 1792db781477SPatrick Sanan .seealso: `PetscDTGaussQuadrature()`, `PetscDTLegendreEval()` 1793744bafbcSMatthew G. Knepley @*/ 17949371c9d4SSatish Balay PetscErrorCode PetscDTGaussTensorQuadrature(PetscInt dim, PetscInt Nc, PetscInt npoints, PetscReal a, PetscReal b, PetscQuadrature *q) { 1795a6b92713SMatthew G. Knepley PetscInt totpoints = dim > 1 ? dim > 2 ? npoints * PetscSqr(npoints) : PetscSqr(npoints) : npoints, i, j, k, c; 1796744bafbcSMatthew G. Knepley PetscReal *x, *w, *xw, *ww; 1797744bafbcSMatthew G. Knepley 1798744bafbcSMatthew G. Knepley PetscFunctionBegin; 17999566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(totpoints * dim, &x)); 18009566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(totpoints * Nc, &w)); 1801744bafbcSMatthew G. Knepley /* Set up the Golub-Welsch system */ 1802744bafbcSMatthew G. Knepley switch (dim) { 1803744bafbcSMatthew G. Knepley case 0: 18049566063dSJacob Faibussowitsch PetscCall(PetscFree(x)); 18059566063dSJacob Faibussowitsch PetscCall(PetscFree(w)); 18069566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(1, &x)); 18079566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(Nc, &w)); 1808744bafbcSMatthew G. Knepley x[0] = 0.0; 1809a6b92713SMatthew G. Knepley for (c = 0; c < Nc; ++c) w[c] = 1.0; 1810744bafbcSMatthew G. Knepley break; 1811744bafbcSMatthew G. Knepley case 1: 18129566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(npoints, &ww)); 18139566063dSJacob Faibussowitsch PetscCall(PetscDTGaussQuadrature(npoints, a, b, x, ww)); 18149371c9d4SSatish Balay for (i = 0; i < npoints; ++i) 18159371c9d4SSatish Balay for (c = 0; c < Nc; ++c) w[i * Nc + c] = ww[i]; 18169566063dSJacob Faibussowitsch PetscCall(PetscFree(ww)); 1817744bafbcSMatthew G. Knepley break; 1818744bafbcSMatthew G. Knepley case 2: 18199566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(npoints, &xw, npoints, &ww)); 18209566063dSJacob Faibussowitsch PetscCall(PetscDTGaussQuadrature(npoints, a, b, xw, ww)); 1821744bafbcSMatthew G. Knepley for (i = 0; i < npoints; ++i) { 1822744bafbcSMatthew G. Knepley for (j = 0; j < npoints; ++j) { 1823744bafbcSMatthew G. Knepley x[(i * npoints + j) * dim + 0] = xw[i]; 1824744bafbcSMatthew G. Knepley x[(i * npoints + j) * dim + 1] = xw[j]; 1825a6b92713SMatthew G. Knepley for (c = 0; c < Nc; ++c) w[(i * npoints + j) * Nc + c] = ww[i] * ww[j]; 1826744bafbcSMatthew G. Knepley } 1827744bafbcSMatthew G. Knepley } 18289566063dSJacob Faibussowitsch PetscCall(PetscFree2(xw, ww)); 1829744bafbcSMatthew G. Knepley break; 1830744bafbcSMatthew G. Knepley case 3: 18319566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(npoints, &xw, npoints, &ww)); 18329566063dSJacob Faibussowitsch PetscCall(PetscDTGaussQuadrature(npoints, a, b, xw, ww)); 1833744bafbcSMatthew G. Knepley for (i = 0; i < npoints; ++i) { 1834744bafbcSMatthew G. Knepley for (j = 0; j < npoints; ++j) { 1835744bafbcSMatthew G. Knepley for (k = 0; k < npoints; ++k) { 1836744bafbcSMatthew G. Knepley x[((i * npoints + j) * npoints + k) * dim + 0] = xw[i]; 1837744bafbcSMatthew G. Knepley x[((i * npoints + j) * npoints + k) * dim + 1] = xw[j]; 1838744bafbcSMatthew G. Knepley x[((i * npoints + j) * npoints + k) * dim + 2] = xw[k]; 1839a6b92713SMatthew G. Knepley for (c = 0; c < Nc; ++c) w[((i * npoints + j) * npoints + k) * Nc + c] = ww[i] * ww[j] * ww[k]; 1840744bafbcSMatthew G. Knepley } 1841744bafbcSMatthew G. Knepley } 1842744bafbcSMatthew G. Knepley } 18439566063dSJacob Faibussowitsch PetscCall(PetscFree2(xw, ww)); 1844744bafbcSMatthew G. Knepley break; 18459371c9d4SSatish Balay default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct quadrature rule for dimension %" PetscInt_FMT, dim); 1846744bafbcSMatthew G. Knepley } 18479566063dSJacob Faibussowitsch PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, q)); 18489566063dSJacob Faibussowitsch PetscCall(PetscQuadratureSetOrder(*q, 2 * npoints - 1)); 18499566063dSJacob Faibussowitsch PetscCall(PetscQuadratureSetData(*q, dim, Nc, totpoints, x, w)); 18509566063dSJacob Faibussowitsch PetscCall(PetscObjectChangeTypeName((PetscObject)*q, "GaussTensor")); 1851744bafbcSMatthew G. Knepley PetscFunctionReturn(0); 1852744bafbcSMatthew G. Knepley } 1853744bafbcSMatthew G. Knepley 1854f5f57ec0SBarry Smith /*@ 1855e6a796c3SToby Isaac PetscDTStroudConicalQuadrature - create Stroud conical quadrature for a simplex 1856494e7359SMatthew G. Knepley 1857494e7359SMatthew G. Knepley Not Collective 1858494e7359SMatthew G. Knepley 18594165533cSJose E. Roman Input Parameters: 1860494e7359SMatthew G. Knepley + dim - The simplex dimension 1861a6b92713SMatthew G. Knepley . Nc - The number of components 1862dcce0ee2SMatthew G. Knepley . npoints - The number of points in one dimension 1863494e7359SMatthew G. Knepley . a - left end of interval (often-1) 1864494e7359SMatthew G. Knepley - b - right end of interval (often +1) 1865494e7359SMatthew G. Knepley 18664165533cSJose E. Roman Output Parameter: 1867552aa4f7SMatthew G. Knepley . q - A PetscQuadrature object 1868494e7359SMatthew G. Knepley 1869494e7359SMatthew G. Knepley Level: intermediate 1870494e7359SMatthew G. Knepley 1871494e7359SMatthew G. Knepley References: 1872606c0280SSatish Balay . * - Karniadakis and Sherwin. FIAT 1873494e7359SMatthew G. Knepley 1874e6a796c3SToby Isaac Note: For dim == 1, this is Gauss-Legendre quadrature 1875e6a796c3SToby Isaac 1876db781477SPatrick Sanan .seealso: `PetscDTGaussTensorQuadrature()`, `PetscDTGaussQuadrature()` 1877494e7359SMatthew G. Knepley @*/ 18789371c9d4SSatish Balay PetscErrorCode PetscDTStroudConicalQuadrature(PetscInt dim, PetscInt Nc, PetscInt npoints, PetscReal a, PetscReal b, PetscQuadrature *q) { 1879fbdc3dfeSToby Isaac PetscInt totprev, totrem; 1880fbdc3dfeSToby Isaac PetscInt totpoints; 1881fbdc3dfeSToby Isaac PetscReal *p1, *w1; 1882fbdc3dfeSToby Isaac PetscReal *x, *w; 1883fbdc3dfeSToby Isaac PetscInt i, j, k, l, m, pt, c; 1884494e7359SMatthew G. Knepley 1885494e7359SMatthew G. Knepley PetscFunctionBegin; 188608401ef6SPierre Jolivet PetscCheck(!(a != -1.0) && !(b != 1.0), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must use default internal right now"); 1887fbdc3dfeSToby Isaac totpoints = 1; 1888fbdc3dfeSToby Isaac for (i = 0, totpoints = 1; i < dim; i++) totpoints *= npoints; 18899566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(totpoints * dim, &x)); 18909566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(totpoints * Nc, &w)); 18919566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(npoints, &p1, npoints, &w1)); 1892fbdc3dfeSToby Isaac for (i = 0; i < totpoints * Nc; i++) w[i] = 1.; 1893fbdc3dfeSToby Isaac for (i = 0, totprev = 1, totrem = totpoints / npoints; i < dim; i++) { 1894fbdc3dfeSToby Isaac PetscReal mul; 1895fbdc3dfeSToby Isaac 1896fbdc3dfeSToby Isaac mul = PetscPowReal(2., -i); 18979566063dSJacob Faibussowitsch PetscCall(PetscDTGaussJacobiQuadrature(npoints, -1., 1., i, 0.0, p1, w1)); 1898fbdc3dfeSToby Isaac for (pt = 0, l = 0; l < totprev; l++) { 1899fbdc3dfeSToby Isaac for (j = 0; j < npoints; j++) { 1900fbdc3dfeSToby Isaac for (m = 0; m < totrem; m++, pt++) { 1901fbdc3dfeSToby Isaac for (k = 0; k < i; k++) x[pt * dim + k] = (x[pt * dim + k] + 1.) * (1. - p1[j]) * 0.5 - 1.; 1902fbdc3dfeSToby Isaac x[pt * dim + i] = p1[j]; 1903fbdc3dfeSToby Isaac for (c = 0; c < Nc; c++) w[pt * Nc + c] *= mul * w1[j]; 1904494e7359SMatthew G. Knepley } 1905494e7359SMatthew G. Knepley } 1906494e7359SMatthew G. Knepley } 1907fbdc3dfeSToby Isaac totprev *= npoints; 1908fbdc3dfeSToby Isaac totrem /= npoints; 1909494e7359SMatthew G. Knepley } 19109566063dSJacob Faibussowitsch PetscCall(PetscFree2(p1, w1)); 19119566063dSJacob Faibussowitsch PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, q)); 19129566063dSJacob Faibussowitsch PetscCall(PetscQuadratureSetOrder(*q, 2 * npoints - 1)); 19139566063dSJacob Faibussowitsch PetscCall(PetscQuadratureSetData(*q, dim, Nc, totpoints, x, w)); 19149566063dSJacob Faibussowitsch PetscCall(PetscObjectChangeTypeName((PetscObject)*q, "StroudConical")); 1915494e7359SMatthew G. Knepley PetscFunctionReturn(0); 1916494e7359SMatthew G. Knepley } 1917494e7359SMatthew G. Knepley 1918d3c69ad0SToby Isaac static PetscBool MinSymTriQuadCite = PETSC_FALSE; 19199371c9d4SSatish Balay const char MinSymTriQuadCitation[] = "@article{WitherdenVincent2015,\n" 1920d3c69ad0SToby Isaac " title = {On the identification of symmetric quadrature rules for finite element methods},\n" 1921d3c69ad0SToby Isaac " journal = {Computers & Mathematics with Applications},\n" 1922d3c69ad0SToby Isaac " volume = {69},\n" 1923d3c69ad0SToby Isaac " number = {10},\n" 1924d3c69ad0SToby Isaac " pages = {1232-1241},\n" 1925d3c69ad0SToby Isaac " year = {2015},\n" 1926d3c69ad0SToby Isaac " issn = {0898-1221},\n" 1927d3c69ad0SToby Isaac " doi = {10.1016/j.camwa.2015.03.017},\n" 1928d3c69ad0SToby Isaac " url = {https://www.sciencedirect.com/science/article/pii/S0898122115001224},\n" 1929d3c69ad0SToby Isaac " author = {F.D. Witherden and P.E. Vincent},\n" 1930d3c69ad0SToby Isaac "}\n"; 1931d3c69ad0SToby Isaac 1932d3c69ad0SToby Isaac #include "petscdttriquadrules.h" 1933d3c69ad0SToby Isaac 1934d3c69ad0SToby Isaac static PetscBool MinSymTetQuadCite = PETSC_FALSE; 19359371c9d4SSatish Balay const char MinSymTetQuadCitation[] = "@article{JaskowiecSukumar2021\n" 1936d3c69ad0SToby Isaac " author = {Jaskowiec, Jan and Sukumar, N.},\n" 1937d3c69ad0SToby Isaac " title = {High-order symmetric cubature rules for tetrahedra and pyramids},\n" 1938d3c69ad0SToby Isaac " journal = {International Journal for Numerical Methods in Engineering},\n" 1939d3c69ad0SToby Isaac " volume = {122},\n" 1940d3c69ad0SToby Isaac " number = {1},\n" 1941d3c69ad0SToby Isaac " pages = {148-171},\n" 1942d3c69ad0SToby Isaac " doi = {10.1002/nme.6528},\n" 1943d3c69ad0SToby Isaac " url = {https://onlinelibrary.wiley.com/doi/abs/10.1002/nme.6528},\n" 1944d3c69ad0SToby Isaac " eprint = {https://onlinelibrary.wiley.com/doi/pdf/10.1002/nme.6528},\n" 1945d3c69ad0SToby Isaac " year = {2021}\n" 1946d3c69ad0SToby Isaac "}\n"; 1947d3c69ad0SToby Isaac 1948d3c69ad0SToby Isaac #include "petscdttetquadrules.h" 1949d3c69ad0SToby Isaac 1950d3c69ad0SToby Isaac // https://en.wikipedia.org/wiki/Partition_(number_theory) 19519371c9d4SSatish Balay static PetscErrorCode PetscDTPartitionNumber(PetscInt n, PetscInt *p) { 1952d3c69ad0SToby Isaac // sequence A000041 in the OEIS 1953d3c69ad0SToby Isaac const PetscInt partition[] = {1, 1, 2, 3, 5, 7, 11, 15, 22, 30, 42, 56, 77, 101, 135, 176, 231, 297, 385, 490, 627, 792, 1002, 1255, 1575, 1958, 2436, 3010, 3718, 4565, 5604}; 1954d3c69ad0SToby Isaac PetscInt tabulated_max = PETSC_STATIC_ARRAY_LENGTH(partition) - 1; 1955d3c69ad0SToby Isaac 1956d3c69ad0SToby Isaac PetscFunctionBegin; 1957d3c69ad0SToby Isaac PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Partition number not defined for negative number %" PetscInt_FMT, n); 1958d3c69ad0SToby Isaac // not implementing the pentagonal number recurrence, we don't need partition numbers for n that high 1959d3c69ad0SToby Isaac PetscCheck(n <= tabulated_max, PETSC_COMM_SELF, PETSC_ERR_SUP, "Partition numbers only tabulated up to %" PetscInt_FMT ", not computed for %" PetscInt_FMT, tabulated_max, n); 1960d3c69ad0SToby Isaac *p = partition[n]; 1961d3c69ad0SToby Isaac PetscFunctionReturn(0); 1962d3c69ad0SToby Isaac } 1963d3c69ad0SToby Isaac 1964d3c69ad0SToby Isaac /*@ 1965d3c69ad0SToby Isaac PetscDTSimplexQuadrature - Create a quadrature rule for a simplex that exactly integrates polynomials up to a given degree. 1966d3c69ad0SToby Isaac 1967d3c69ad0SToby Isaac Not Collective 1968d3c69ad0SToby Isaac 1969d3c69ad0SToby Isaac Input Parameters: 1970d3c69ad0SToby Isaac + dim - The spatial dimension of the simplex (1 = segment, 2 = triangle, 3 = tetrahedron) 1971d3c69ad0SToby Isaac . degree - The largest polynomial degree that is required to be integrated exactly 1972d3c69ad0SToby Isaac - type - left end of interval (often-1) 1973d3c69ad0SToby Isaac 1974d3c69ad0SToby Isaac Output Parameter: 1975d3c69ad0SToby Isaac . quad - A PetscQuadrature object for integration over the biunit simplex 1976d3c69ad0SToby Isaac (defined by the bounds $x_i >= -1$ and $\sum_i x_i <= 2 - d$) that is exact for 1977d3c69ad0SToby Isaac polynomials up to the given degree 1978d3c69ad0SToby Isaac 1979d3c69ad0SToby Isaac Level: intermediate 1980d3c69ad0SToby Isaac 1981d3c69ad0SToby Isaac .seealso: `PetscDTSimplexQuadratureType`, `PetscDTGaussQuadrature()`, `PetscDTStroudCononicalQuadrature()` 1982d3c69ad0SToby Isaac @*/ 19839371c9d4SSatish Balay PetscErrorCode PetscDTSimplexQuadrature(PetscInt dim, PetscInt degree, PetscDTSimplexQuadratureType type, PetscQuadrature *quad) { 1984d3c69ad0SToby Isaac PetscDTSimplexQuadratureType orig_type = type; 1985d3c69ad0SToby Isaac 1986d3c69ad0SToby Isaac PetscFunctionBegin; 1987d3c69ad0SToby Isaac PetscCheck(dim >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Negative dimension %" PetscInt_FMT, dim); 1988d3c69ad0SToby Isaac PetscCheck(degree >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Negative degree %" PetscInt_FMT, degree); 19899371c9d4SSatish Balay if (type == PETSCDTSIMPLEXQUAD_DEFAULT) { type = PETSCDTSIMPLEXQUAD_MINSYM; } 1990d3c69ad0SToby Isaac if (type == PETSCDTSIMPLEXQUAD_CONIC || dim < 2) { 1991d3c69ad0SToby Isaac PetscInt points_per_dim = (degree + 2) / 2; // ceil((degree + 1) / 2); 1992d3c69ad0SToby Isaac PetscCall(PetscDTStroudConicalQuadrature(dim, 1, points_per_dim, -1, 1, quad)); 1993d3c69ad0SToby Isaac } else { 1994d3c69ad0SToby Isaac PetscInt n = dim + 1; 1995d3c69ad0SToby Isaac PetscInt fact = 1; 1996d3c69ad0SToby Isaac PetscInt *part, *perm; 1997d3c69ad0SToby Isaac PetscInt p = 0; 1998d3c69ad0SToby Isaac PetscInt max_degree; 1999d3c69ad0SToby Isaac const PetscInt *nodes_per_type = NULL; 2000d3c69ad0SToby Isaac const PetscInt *all_num_full_nodes = NULL; 2001d3c69ad0SToby Isaac const PetscReal **weights_list = NULL; 2002d3c69ad0SToby Isaac const PetscReal **compact_nodes_list = NULL; 2003d3c69ad0SToby Isaac const char *citation = NULL; 2004d3c69ad0SToby Isaac PetscBool *cited = NULL; 2005d3c69ad0SToby Isaac 2006d3c69ad0SToby Isaac switch (dim) { 2007d3c69ad0SToby Isaac case 2: 2008d3c69ad0SToby Isaac cited = &MinSymTriQuadCite; 2009d3c69ad0SToby Isaac citation = MinSymTriQuadCitation; 2010d3c69ad0SToby Isaac max_degree = PetscDTWVTriQuad_max_degree; 2011d3c69ad0SToby Isaac nodes_per_type = PetscDTWVTriQuad_num_orbits; 2012d3c69ad0SToby Isaac all_num_full_nodes = PetscDTWVTriQuad_num_nodes; 2013d3c69ad0SToby Isaac weights_list = PetscDTWVTriQuad_weights; 2014d3c69ad0SToby Isaac compact_nodes_list = PetscDTWVTriQuad_orbits; 2015d3c69ad0SToby Isaac break; 2016d3c69ad0SToby Isaac case 3: 2017d3c69ad0SToby Isaac cited = &MinSymTetQuadCite; 2018d3c69ad0SToby Isaac citation = MinSymTetQuadCitation; 2019d3c69ad0SToby Isaac max_degree = PetscDTJSTetQuad_max_degree; 2020d3c69ad0SToby Isaac nodes_per_type = PetscDTJSTetQuad_num_orbits; 2021d3c69ad0SToby Isaac all_num_full_nodes = PetscDTJSTetQuad_num_nodes; 2022d3c69ad0SToby Isaac weights_list = PetscDTJSTetQuad_weights; 2023d3c69ad0SToby Isaac compact_nodes_list = PetscDTJSTetQuad_orbits; 2024d3c69ad0SToby Isaac break; 20259371c9d4SSatish Balay default: max_degree = -1; break; 2026d3c69ad0SToby Isaac } 2027d3c69ad0SToby Isaac 2028d3c69ad0SToby Isaac if (degree > max_degree) { 2029d3c69ad0SToby Isaac if (orig_type == PETSCDTSIMPLEXQUAD_DEFAULT) { 2030d3c69ad0SToby Isaac // fall back to conic 2031d3c69ad0SToby Isaac PetscCall(PetscDTSimplexQuadrature(dim, degree, PETSCDTSIMPLEXQUAD_CONIC, quad)); 2032d3c69ad0SToby Isaac PetscFunctionReturn(0); 2033d3c69ad0SToby Isaac } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Minimal symmetric quadrature for dim %" PetscInt_FMT ", degree %" PetscInt_FMT " unsupported", dim, degree); 2034d3c69ad0SToby Isaac } 2035d3c69ad0SToby Isaac 2036d3c69ad0SToby Isaac PetscCall(PetscCitationsRegister(citation, cited)); 2037d3c69ad0SToby Isaac 2038d3c69ad0SToby Isaac PetscCall(PetscDTPartitionNumber(n, &p)); 2039d3c69ad0SToby Isaac for (PetscInt d = 2; d <= n; d++) fact *= d; 2040d3c69ad0SToby Isaac 2041d3c69ad0SToby Isaac PetscInt num_full_nodes = all_num_full_nodes[degree]; 2042d3c69ad0SToby Isaac const PetscReal *all_compact_nodes = compact_nodes_list[degree]; 2043d3c69ad0SToby Isaac const PetscReal *all_compact_weights = weights_list[degree]; 2044d3c69ad0SToby Isaac nodes_per_type = &nodes_per_type[p * degree]; 2045d3c69ad0SToby Isaac 2046d3c69ad0SToby Isaac PetscReal *points; 2047d3c69ad0SToby Isaac PetscReal *counts; 2048d3c69ad0SToby Isaac PetscReal *weights; 2049d3c69ad0SToby Isaac PetscReal *bary_to_biunit; // row-major transformation of barycentric coordinate to biunit 2050d3c69ad0SToby Isaac PetscQuadrature q; 2051d3c69ad0SToby Isaac 2052d3c69ad0SToby Isaac // compute the transformation 2053d3c69ad0SToby Isaac PetscCall(PetscMalloc1(n * dim, &bary_to_biunit)); 2054d3c69ad0SToby Isaac for (PetscInt d = 0; d < dim; d++) { 20559371c9d4SSatish Balay for (PetscInt b = 0; b < n; b++) { bary_to_biunit[d * n + b] = (d == b) ? 1.0 : -1.0; } 2056d3c69ad0SToby Isaac } 2057d3c69ad0SToby Isaac 2058d3c69ad0SToby Isaac PetscCall(PetscMalloc3(n, &part, n, &perm, n, &counts)); 2059d3c69ad0SToby Isaac PetscCall(PetscCalloc1(num_full_nodes * dim, &points)); 2060d3c69ad0SToby Isaac PetscCall(PetscMalloc1(num_full_nodes, &weights)); 2061d3c69ad0SToby Isaac 2062d3c69ad0SToby Isaac // (0, 0, ...) is the first partition lexicographically 2063d3c69ad0SToby Isaac PetscCall(PetscArrayzero(part, n)); 2064d3c69ad0SToby Isaac PetscCall(PetscArrayzero(counts, n)); 2065d3c69ad0SToby Isaac counts[0] = n; 2066d3c69ad0SToby Isaac 2067d3c69ad0SToby Isaac // for each partition 2068d3c69ad0SToby Isaac for (PetscInt s = 0, node_offset = 0; s < p; s++) { 2069d3c69ad0SToby Isaac PetscInt num_compact_coords = part[n - 1] + 1; 2070d3c69ad0SToby Isaac 2071d3c69ad0SToby Isaac const PetscReal *compact_nodes = all_compact_nodes; 2072d3c69ad0SToby Isaac const PetscReal *compact_weights = all_compact_weights; 2073d3c69ad0SToby Isaac all_compact_nodes += num_compact_coords * nodes_per_type[s]; 2074d3c69ad0SToby Isaac all_compact_weights += nodes_per_type[s]; 2075d3c69ad0SToby Isaac 2076d3c69ad0SToby Isaac // for every permutation of the vertices 2077d3c69ad0SToby Isaac for (PetscInt f = 0; f < fact; f++) { 2078d3c69ad0SToby Isaac PetscCall(PetscDTEnumPerm(n, f, perm, NULL)); 2079d3c69ad0SToby Isaac 2080d3c69ad0SToby Isaac // check if it is a valid permutation 2081d3c69ad0SToby Isaac PetscInt digit; 2082d3c69ad0SToby Isaac for (digit = 1; digit < n; digit++) { 2083d3c69ad0SToby Isaac // skip permutations that would duplicate a node because it has a smaller symmetry group 2084d3c69ad0SToby Isaac if (part[digit - 1] == part[digit] && perm[digit - 1] > perm[digit]) break; 2085d3c69ad0SToby Isaac } 2086d3c69ad0SToby Isaac if (digit < n) continue; 2087d3c69ad0SToby Isaac 2088d3c69ad0SToby Isaac // create full nodes from this permutation of the compact nodes 2089d3c69ad0SToby Isaac PetscReal *full_nodes = &points[node_offset * dim]; 2090d3c69ad0SToby Isaac PetscReal *full_weights = &weights[node_offset]; 2091d3c69ad0SToby Isaac 2092d3c69ad0SToby Isaac PetscCall(PetscArraycpy(full_weights, compact_weights, nodes_per_type[s])); 2093d3c69ad0SToby Isaac for (PetscInt b = 0; b < n; b++) { 2094d3c69ad0SToby Isaac for (PetscInt d = 0; d < dim; d++) { 20959371c9d4SSatish Balay for (PetscInt node = 0; node < nodes_per_type[s]; node++) { full_nodes[node * dim + d] += bary_to_biunit[d * n + perm[b]] * compact_nodes[node * num_compact_coords + part[b]]; } 2096d3c69ad0SToby Isaac } 2097d3c69ad0SToby Isaac } 2098d3c69ad0SToby Isaac node_offset += nodes_per_type[s]; 2099d3c69ad0SToby Isaac } 2100d3c69ad0SToby Isaac 2101d3c69ad0SToby Isaac if (s < p - 1) { // Generate the next partition 2102d3c69ad0SToby Isaac /* A partition is described by the number of coordinates that are in 2103d3c69ad0SToby Isaac * each set of duplicates (counts) and redundantly by mapping each 2104d3c69ad0SToby Isaac * index to its set of duplicates (part) 2105d3c69ad0SToby Isaac * 2106d3c69ad0SToby Isaac * Counts should always be in nonincreasing order 2107d3c69ad0SToby Isaac * 2108d3c69ad0SToby Isaac * We want to generate the partitions lexically by part, which means 2109d3c69ad0SToby Isaac * finding the last index where count > 1 and reducing by 1. 2110d3c69ad0SToby Isaac * 2111d3c69ad0SToby Isaac * For the new counts beyond that index, we eagerly assign the remaining 2112d3c69ad0SToby Isaac * capacity of the partition to smaller indices (ensures lexical ordering), 2113d3c69ad0SToby Isaac * while respecting the nonincreasing invariant of the counts 2114d3c69ad0SToby Isaac */ 2115d3c69ad0SToby Isaac PetscInt last_digit = part[n - 1]; 2116d3c69ad0SToby Isaac PetscInt last_digit_with_extra = last_digit; 2117d3c69ad0SToby Isaac while (counts[last_digit_with_extra] == 1) last_digit_with_extra--; 2118d3c69ad0SToby Isaac PetscInt limit = --counts[last_digit_with_extra]; 2119d3c69ad0SToby Isaac PetscInt total_to_distribute = last_digit - last_digit_with_extra + 1; 2120d3c69ad0SToby Isaac for (PetscInt digit = last_digit_with_extra + 1; digit < n; digit++) { 2121d3c69ad0SToby Isaac counts[digit] = PetscMin(limit, total_to_distribute); 2122d3c69ad0SToby Isaac total_to_distribute -= PetscMin(limit, total_to_distribute); 2123d3c69ad0SToby Isaac } 2124d3c69ad0SToby Isaac for (PetscInt digit = 0, offset = 0; digit < n; digit++) { 2125d3c69ad0SToby Isaac PetscInt count = counts[digit]; 21269371c9d4SSatish Balay for (PetscInt c = 0; c < count; c++) { part[offset++] = digit; } 2127d3c69ad0SToby Isaac } 2128d3c69ad0SToby Isaac } 2129d3c69ad0SToby Isaac } 2130d3c69ad0SToby Isaac PetscCall(PetscFree3(part, perm, counts)); 2131d3c69ad0SToby Isaac PetscCall(PetscFree(bary_to_biunit)); 2132d3c69ad0SToby Isaac PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, &q)); 2133d3c69ad0SToby Isaac PetscCall(PetscQuadratureSetData(q, dim, 1, num_full_nodes, points, weights)); 2134d3c69ad0SToby Isaac *quad = q; 2135d3c69ad0SToby Isaac } 2136d3c69ad0SToby Isaac PetscFunctionReturn(0); 2137d3c69ad0SToby Isaac } 2138d3c69ad0SToby Isaac 2139f5f57ec0SBarry Smith /*@ 2140b3c0f97bSTom Klotz PetscDTTanhSinhTensorQuadrature - create tanh-sinh quadrature for a tensor product cell 2141b3c0f97bSTom Klotz 2142b3c0f97bSTom Klotz Not Collective 2143b3c0f97bSTom Klotz 21444165533cSJose E. Roman Input Parameters: 2145b3c0f97bSTom Klotz + dim - The cell dimension 2146b3c0f97bSTom Klotz . level - The number of points in one dimension, 2^l 2147b3c0f97bSTom Klotz . a - left end of interval (often-1) 2148b3c0f97bSTom Klotz - b - right end of interval (often +1) 2149b3c0f97bSTom Klotz 21504165533cSJose E. Roman Output Parameter: 2151b3c0f97bSTom Klotz . q - A PetscQuadrature object 2152b3c0f97bSTom Klotz 2153b3c0f97bSTom Klotz Level: intermediate 2154b3c0f97bSTom Klotz 2155db781477SPatrick Sanan .seealso: `PetscDTGaussTensorQuadrature()` 2156b3c0f97bSTom Klotz @*/ 21579371c9d4SSatish Balay PetscErrorCode PetscDTTanhSinhTensorQuadrature(PetscInt dim, PetscInt level, PetscReal a, PetscReal b, PetscQuadrature *q) { 2158b3c0f97bSTom Klotz const PetscInt p = 16; /* Digits of precision in the evaluation */ 2159b3c0f97bSTom Klotz const PetscReal alpha = (b - a) / 2.; /* Half-width of the integration interval */ 2160b3c0f97bSTom Klotz const PetscReal beta = (b + a) / 2.; /* Center of the integration interval */ 2161b3c0f97bSTom Klotz const PetscReal h = PetscPowReal(2.0, -level); /* Step size, length between x_k */ 2162d84b4d08SMatthew G. Knepley PetscReal xk; /* Quadrature point x_k on reference domain [-1, 1] */ 2163b3c0f97bSTom Klotz PetscReal wk = 0.5 * PETSC_PI; /* Quadrature weight at x_k */ 2164b3c0f97bSTom Klotz PetscReal *x, *w; 2165b3c0f97bSTom Klotz PetscInt K, k, npoints; 2166b3c0f97bSTom Klotz 2167b3c0f97bSTom Klotz PetscFunctionBegin; 216863a3b9bcSJacob Faibussowitsch PetscCheck(dim <= 1, PETSC_COMM_SELF, PETSC_ERR_SUP, "Dimension %" PetscInt_FMT " not yet implemented", dim); 216928b400f6SJacob Faibussowitsch PetscCheck(level, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must give a number of significant digits"); 2170b3c0f97bSTom Klotz /* Find K such that the weights are < 32 digits of precision */ 21719371c9d4SSatish Balay for (K = 1; PetscAbsReal(PetscLog10Real(wk)) < 2 * p; ++K) { wk = 0.5 * h * PETSC_PI * PetscCoshReal(K * h) / PetscSqr(PetscCoshReal(0.5 * PETSC_PI * PetscSinhReal(K * h))); } 21729566063dSJacob Faibussowitsch PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, q)); 21739566063dSJacob Faibussowitsch PetscCall(PetscQuadratureSetOrder(*q, 2 * K + 1)); 2174b3c0f97bSTom Klotz npoints = 2 * K - 1; 21759566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(npoints * dim, &x)); 21769566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(npoints, &w)); 2177b3c0f97bSTom Klotz /* Center term */ 2178b3c0f97bSTom Klotz x[0] = beta; 2179b3c0f97bSTom Klotz w[0] = 0.5 * alpha * PETSC_PI; 2180b3c0f97bSTom Klotz for (k = 1; k < K; ++k) { 21819add2064SThomas Klotz wk = 0.5 * alpha * h * PETSC_PI * PetscCoshReal(k * h) / PetscSqr(PetscCoshReal(0.5 * PETSC_PI * PetscSinhReal(k * h))); 21821118d4bcSLisandro Dalcin xk = PetscTanhReal(0.5 * PETSC_PI * PetscSinhReal(k * h)); 2183b3c0f97bSTom Klotz x[2 * k - 1] = -alpha * xk + beta; 2184b3c0f97bSTom Klotz w[2 * k - 1] = wk; 2185b3c0f97bSTom Klotz x[2 * k + 0] = alpha * xk + beta; 2186b3c0f97bSTom Klotz w[2 * k + 0] = wk; 2187b3c0f97bSTom Klotz } 21889566063dSJacob Faibussowitsch PetscCall(PetscQuadratureSetData(*q, dim, 1, npoints, x, w)); 2189b3c0f97bSTom Klotz PetscFunctionReturn(0); 2190b3c0f97bSTom Klotz } 2191b3c0f97bSTom Klotz 21929371c9d4SSatish Balay PetscErrorCode PetscDTTanhSinhIntegrate(void (*func)(const PetscReal[], void *, PetscReal *), PetscReal a, PetscReal b, PetscInt digits, void *ctx, PetscReal *sol) { 2193b3c0f97bSTom Klotz const PetscInt p = 16; /* Digits of precision in the evaluation */ 2194b3c0f97bSTom Klotz const PetscReal alpha = (b - a) / 2.; /* Half-width of the integration interval */ 2195b3c0f97bSTom Klotz const PetscReal beta = (b + a) / 2.; /* Center of the integration interval */ 2196b3c0f97bSTom Klotz PetscReal h = 1.0; /* Step size, length between x_k */ 2197b3c0f97bSTom Klotz PetscInt l = 0; /* Level of refinement, h = 2^{-l} */ 2198b3c0f97bSTom Klotz PetscReal osum = 0.0; /* Integral on last level */ 2199b3c0f97bSTom Klotz PetscReal psum = 0.0; /* Integral on the level before the last level */ 2200b3c0f97bSTom Klotz PetscReal sum; /* Integral on current level */ 2201446c295cSMatthew G. Knepley PetscReal yk; /* Quadrature point 1 - x_k on reference domain [-1, 1] */ 2202b3c0f97bSTom Klotz PetscReal lx, rx; /* Quadrature points to the left and right of 0 on the real domain [a, b] */ 2203b3c0f97bSTom Klotz PetscReal wk; /* Quadrature weight at x_k */ 2204b3c0f97bSTom Klotz PetscReal lval, rval; /* Terms in the quadature sum to the left and right of 0 */ 2205b3c0f97bSTom Klotz PetscInt d; /* Digits of precision in the integral */ 2206b3c0f97bSTom Klotz 2207b3c0f97bSTom Klotz PetscFunctionBegin; 220808401ef6SPierre Jolivet PetscCheck(digits > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must give a positive number of significant digits"); 2209b3c0f97bSTom Klotz /* Center term */ 2210d6685f55SMatthew G. Knepley func(&beta, ctx, &lval); 2211b3c0f97bSTom Klotz sum = 0.5 * alpha * PETSC_PI * lval; 2212b3c0f97bSTom Klotz /* */ 2213b3c0f97bSTom Klotz do { 2214b3c0f97bSTom Klotz PetscReal lterm, rterm, maxTerm = 0.0, d1, d2, d3, d4; 2215b3c0f97bSTom Klotz PetscInt k = 1; 2216b3c0f97bSTom Klotz 2217b3c0f97bSTom Klotz ++l; 221863a3b9bcSJacob Faibussowitsch /* PetscPrintf(PETSC_COMM_SELF, "LEVEL %" PetscInt_FMT " sum: %15.15f\n", l, sum); */ 2219b3c0f97bSTom Klotz /* At each level of refinement, h --> h/2 and sum --> sum/2 */ 2220b3c0f97bSTom Klotz psum = osum; 2221b3c0f97bSTom Klotz osum = sum; 2222b3c0f97bSTom Klotz h *= 0.5; 2223b3c0f97bSTom Klotz sum *= 0.5; 2224b3c0f97bSTom Klotz do { 22259add2064SThomas Klotz wk = 0.5 * h * PETSC_PI * PetscCoshReal(k * h) / PetscSqr(PetscCoshReal(0.5 * PETSC_PI * PetscSinhReal(k * h))); 2226446c295cSMatthew G. Knepley yk = 1.0 / (PetscExpReal(0.5 * PETSC_PI * PetscSinhReal(k * h)) * PetscCoshReal(0.5 * PETSC_PI * PetscSinhReal(k * h))); 2227446c295cSMatthew G. Knepley lx = -alpha * (1.0 - yk) + beta; 2228446c295cSMatthew G. Knepley rx = alpha * (1.0 - yk) + beta; 2229d6685f55SMatthew G. Knepley func(&lx, ctx, &lval); 2230d6685f55SMatthew G. Knepley func(&rx, ctx, &rval); 2231b3c0f97bSTom Klotz lterm = alpha * wk * lval; 2232b3c0f97bSTom Klotz maxTerm = PetscMax(PetscAbsReal(lterm), maxTerm); 2233b3c0f97bSTom Klotz sum += lterm; 2234b3c0f97bSTom Klotz rterm = alpha * wk * rval; 2235b3c0f97bSTom Klotz maxTerm = PetscMax(PetscAbsReal(rterm), maxTerm); 2236b3c0f97bSTom Klotz sum += rterm; 2237b3c0f97bSTom Klotz ++k; 2238b3c0f97bSTom Klotz /* Only need to evaluate every other point on refined levels */ 2239b3c0f97bSTom Klotz if (l != 1) ++k; 22409add2064SThomas Klotz } while (PetscAbsReal(PetscLog10Real(wk)) < p); /* Only need to evaluate sum until weights are < 32 digits of precision */ 2241b3c0f97bSTom Klotz 2242b3c0f97bSTom Klotz d1 = PetscLog10Real(PetscAbsReal(sum - osum)); 2243b3c0f97bSTom Klotz d2 = PetscLog10Real(PetscAbsReal(sum - psum)); 2244b3c0f97bSTom Klotz d3 = PetscLog10Real(maxTerm) - p; 224509d48545SBarry Smith if (PetscMax(PetscAbsReal(lterm), PetscAbsReal(rterm)) == 0.0) d4 = 0.0; 224609d48545SBarry Smith else d4 = PetscLog10Real(PetscMax(PetscAbsReal(lterm), PetscAbsReal(rterm))); 2247b3c0f97bSTom Klotz d = PetscAbsInt(PetscMin(0, PetscMax(PetscMax(PetscMax(PetscSqr(d1) / d2, 2 * d1), d3), d4))); 22489add2064SThomas Klotz } while (d < digits && l < 12); 2249b3c0f97bSTom Klotz *sol = sum; 2250e510cb1fSThomas Klotz 2251b3c0f97bSTom Klotz PetscFunctionReturn(0); 2252b3c0f97bSTom Klotz } 2253b3c0f97bSTom Klotz 2254497880caSRichard Tran Mills #if defined(PETSC_HAVE_MPFR) 22559371c9d4SSatish Balay PetscErrorCode PetscDTTanhSinhIntegrateMPFR(void (*func)(const PetscReal[], void *, PetscReal *), PetscReal a, PetscReal b, PetscInt digits, void *ctx, PetscReal *sol) { 2256e510cb1fSThomas Klotz const PetscInt safetyFactor = 2; /* Calculate abcissa until 2*p digits */ 225729f144ccSMatthew G. Knepley PetscInt l = 0; /* Level of refinement, h = 2^{-l} */ 225829f144ccSMatthew G. Knepley mpfr_t alpha; /* Half-width of the integration interval */ 225929f144ccSMatthew G. Knepley mpfr_t beta; /* Center of the integration interval */ 226029f144ccSMatthew G. Knepley mpfr_t h; /* Step size, length between x_k */ 226129f144ccSMatthew G. Knepley mpfr_t osum; /* Integral on last level */ 226229f144ccSMatthew G. Knepley mpfr_t psum; /* Integral on the level before the last level */ 226329f144ccSMatthew G. Knepley mpfr_t sum; /* Integral on current level */ 226429f144ccSMatthew G. Knepley mpfr_t yk; /* Quadrature point 1 - x_k on reference domain [-1, 1] */ 226529f144ccSMatthew G. Knepley mpfr_t lx, rx; /* Quadrature points to the left and right of 0 on the real domain [a, b] */ 226629f144ccSMatthew G. Knepley mpfr_t wk; /* Quadrature weight at x_k */ 22671fbc92bbSMatthew G. Knepley PetscReal lval, rval, rtmp; /* Terms in the quadature sum to the left and right of 0 */ 226829f144ccSMatthew G. Knepley PetscInt d; /* Digits of precision in the integral */ 226929f144ccSMatthew G. Knepley mpfr_t pi2, kh, msinh, mcosh, maxTerm, curTerm, tmp; 227029f144ccSMatthew G. Knepley 227129f144ccSMatthew G. Knepley PetscFunctionBegin; 227208401ef6SPierre Jolivet PetscCheck(digits > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must give a positive number of significant digits"); 227329f144ccSMatthew G. Knepley /* Create high precision storage */ 2274c9f744b5SMatthew 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); 227529f144ccSMatthew G. Knepley /* Initialization */ 227629f144ccSMatthew G. Knepley mpfr_set_d(alpha, 0.5 * (b - a), MPFR_RNDN); 227729f144ccSMatthew G. Knepley mpfr_set_d(beta, 0.5 * (b + a), MPFR_RNDN); 227829f144ccSMatthew G. Knepley mpfr_set_d(osum, 0.0, MPFR_RNDN); 227929f144ccSMatthew G. Knepley mpfr_set_d(psum, 0.0, MPFR_RNDN); 228029f144ccSMatthew G. Knepley mpfr_set_d(h, 1.0, MPFR_RNDN); 228129f144ccSMatthew G. Knepley mpfr_const_pi(pi2, MPFR_RNDN); 228229f144ccSMatthew G. Knepley mpfr_mul_d(pi2, pi2, 0.5, MPFR_RNDN); 228329f144ccSMatthew G. Knepley /* Center term */ 22841fbc92bbSMatthew G. Knepley rtmp = 0.5 * (b + a); 22851fbc92bbSMatthew G. Knepley func(&rtmp, ctx, &lval); 228629f144ccSMatthew G. Knepley mpfr_set(sum, pi2, MPFR_RNDN); 228729f144ccSMatthew G. Knepley mpfr_mul(sum, sum, alpha, MPFR_RNDN); 228829f144ccSMatthew G. Knepley mpfr_mul_d(sum, sum, lval, MPFR_RNDN); 228929f144ccSMatthew G. Knepley /* */ 229029f144ccSMatthew G. Knepley do { 229129f144ccSMatthew G. Knepley PetscReal d1, d2, d3, d4; 229229f144ccSMatthew G. Knepley PetscInt k = 1; 229329f144ccSMatthew G. Knepley 229429f144ccSMatthew G. Knepley ++l; 229529f144ccSMatthew G. Knepley mpfr_set_d(maxTerm, 0.0, MPFR_RNDN); 229663a3b9bcSJacob Faibussowitsch /* PetscPrintf(PETSC_COMM_SELF, "LEVEL %" PetscInt_FMT " sum: %15.15f\n", l, sum); */ 229729f144ccSMatthew G. Knepley /* At each level of refinement, h --> h/2 and sum --> sum/2 */ 229829f144ccSMatthew G. Knepley mpfr_set(psum, osum, MPFR_RNDN); 229929f144ccSMatthew G. Knepley mpfr_set(osum, sum, MPFR_RNDN); 230029f144ccSMatthew G. Knepley mpfr_mul_d(h, h, 0.5, MPFR_RNDN); 230129f144ccSMatthew G. Knepley mpfr_mul_d(sum, sum, 0.5, MPFR_RNDN); 230229f144ccSMatthew G. Knepley do { 230329f144ccSMatthew G. Knepley mpfr_set_si(kh, k, MPFR_RNDN); 230429f144ccSMatthew G. Knepley mpfr_mul(kh, kh, h, MPFR_RNDN); 230529f144ccSMatthew G. Knepley /* Weight */ 230629f144ccSMatthew G. Knepley mpfr_set(wk, h, MPFR_RNDN); 230729f144ccSMatthew G. Knepley mpfr_sinh_cosh(msinh, mcosh, kh, MPFR_RNDN); 230829f144ccSMatthew G. Knepley mpfr_mul(msinh, msinh, pi2, MPFR_RNDN); 230929f144ccSMatthew G. Knepley mpfr_mul(mcosh, mcosh, pi2, MPFR_RNDN); 231029f144ccSMatthew G. Knepley mpfr_cosh(tmp, msinh, MPFR_RNDN); 231129f144ccSMatthew G. Knepley mpfr_sqr(tmp, tmp, MPFR_RNDN); 231229f144ccSMatthew G. Knepley mpfr_mul(wk, wk, mcosh, MPFR_RNDN); 231329f144ccSMatthew G. Knepley mpfr_div(wk, wk, tmp, MPFR_RNDN); 231429f144ccSMatthew G. Knepley /* Abscissa */ 231529f144ccSMatthew G. Knepley mpfr_set_d(yk, 1.0, MPFR_RNDZ); 231629f144ccSMatthew G. Knepley mpfr_cosh(tmp, msinh, MPFR_RNDN); 231729f144ccSMatthew G. Knepley mpfr_div(yk, yk, tmp, MPFR_RNDZ); 231829f144ccSMatthew G. Knepley mpfr_exp(tmp, msinh, MPFR_RNDN); 231929f144ccSMatthew G. Knepley mpfr_div(yk, yk, tmp, MPFR_RNDZ); 232029f144ccSMatthew G. Knepley /* Quadrature points */ 232129f144ccSMatthew G. Knepley mpfr_sub_d(lx, yk, 1.0, MPFR_RNDZ); 232229f144ccSMatthew G. Knepley mpfr_mul(lx, lx, alpha, MPFR_RNDU); 232329f144ccSMatthew G. Knepley mpfr_add(lx, lx, beta, MPFR_RNDU); 232429f144ccSMatthew G. Knepley mpfr_d_sub(rx, 1.0, yk, MPFR_RNDZ); 232529f144ccSMatthew G. Knepley mpfr_mul(rx, rx, alpha, MPFR_RNDD); 232629f144ccSMatthew G. Knepley mpfr_add(rx, rx, beta, MPFR_RNDD); 232729f144ccSMatthew G. Knepley /* Evaluation */ 23281fbc92bbSMatthew G. Knepley rtmp = mpfr_get_d(lx, MPFR_RNDU); 23291fbc92bbSMatthew G. Knepley func(&rtmp, ctx, &lval); 23301fbc92bbSMatthew G. Knepley rtmp = mpfr_get_d(rx, MPFR_RNDD); 23311fbc92bbSMatthew G. Knepley func(&rtmp, ctx, &rval); 233229f144ccSMatthew G. Knepley /* Update */ 233329f144ccSMatthew G. Knepley mpfr_mul(tmp, wk, alpha, MPFR_RNDN); 233429f144ccSMatthew G. Knepley mpfr_mul_d(tmp, tmp, lval, MPFR_RNDN); 233529f144ccSMatthew G. Knepley mpfr_add(sum, sum, tmp, MPFR_RNDN); 233629f144ccSMatthew G. Knepley mpfr_abs(tmp, tmp, MPFR_RNDN); 233729f144ccSMatthew G. Knepley mpfr_max(maxTerm, maxTerm, tmp, MPFR_RNDN); 233829f144ccSMatthew G. Knepley mpfr_set(curTerm, tmp, MPFR_RNDN); 233929f144ccSMatthew G. Knepley mpfr_mul(tmp, wk, alpha, MPFR_RNDN); 234029f144ccSMatthew G. Knepley mpfr_mul_d(tmp, tmp, rval, MPFR_RNDN); 234129f144ccSMatthew G. Knepley mpfr_add(sum, sum, tmp, MPFR_RNDN); 234229f144ccSMatthew G. Knepley mpfr_abs(tmp, tmp, MPFR_RNDN); 234329f144ccSMatthew G. Knepley mpfr_max(maxTerm, maxTerm, tmp, MPFR_RNDN); 234429f144ccSMatthew G. Knepley mpfr_max(curTerm, curTerm, tmp, MPFR_RNDN); 234529f144ccSMatthew G. Knepley ++k; 234629f144ccSMatthew G. Knepley /* Only need to evaluate every other point on refined levels */ 234729f144ccSMatthew G. Knepley if (l != 1) ++k; 234829f144ccSMatthew G. Knepley mpfr_log10(tmp, wk, MPFR_RNDN); 234929f144ccSMatthew G. Knepley mpfr_abs(tmp, tmp, MPFR_RNDN); 2350c9f744b5SMatthew G. Knepley } while (mpfr_get_d(tmp, MPFR_RNDN) < safetyFactor * digits); /* Only need to evaluate sum until weights are < 32 digits of precision */ 235129f144ccSMatthew G. Knepley mpfr_sub(tmp, sum, osum, MPFR_RNDN); 235229f144ccSMatthew G. Knepley mpfr_abs(tmp, tmp, MPFR_RNDN); 235329f144ccSMatthew G. Knepley mpfr_log10(tmp, tmp, MPFR_RNDN); 235429f144ccSMatthew G. Knepley d1 = mpfr_get_d(tmp, MPFR_RNDN); 235529f144ccSMatthew G. Knepley mpfr_sub(tmp, sum, psum, MPFR_RNDN); 235629f144ccSMatthew G. Knepley mpfr_abs(tmp, tmp, MPFR_RNDN); 235729f144ccSMatthew G. Knepley mpfr_log10(tmp, tmp, MPFR_RNDN); 235829f144ccSMatthew G. Knepley d2 = mpfr_get_d(tmp, MPFR_RNDN); 235929f144ccSMatthew G. Knepley mpfr_log10(tmp, maxTerm, MPFR_RNDN); 2360c9f744b5SMatthew G. Knepley d3 = mpfr_get_d(tmp, MPFR_RNDN) - digits; 236129f144ccSMatthew G. Knepley mpfr_log10(tmp, curTerm, MPFR_RNDN); 236229f144ccSMatthew G. Knepley d4 = mpfr_get_d(tmp, MPFR_RNDN); 236329f144ccSMatthew G. Knepley d = PetscAbsInt(PetscMin(0, PetscMax(PetscMax(PetscMax(PetscSqr(d1) / d2, 2 * d1), d3), d4))); 2364b0649871SThomas Klotz } while (d < digits && l < 8); 236529f144ccSMatthew G. Knepley *sol = mpfr_get_d(sum, MPFR_RNDN); 236629f144ccSMatthew G. Knepley /* Cleanup */ 236729f144ccSMatthew G. Knepley mpfr_clears(alpha, beta, h, sum, osum, psum, yk, wk, lx, rx, tmp, maxTerm, curTerm, pi2, kh, msinh, mcosh, NULL); 236829f144ccSMatthew G. Knepley PetscFunctionReturn(0); 236929f144ccSMatthew G. Knepley } 2370d525116cSMatthew G. Knepley #else 2371fbfcfee5SBarry Smith 23729371c9d4SSatish Balay PetscErrorCode PetscDTTanhSinhIntegrateMPFR(void (*func)(const PetscReal[], void *, PetscReal *), PetscReal a, PetscReal b, PetscInt digits, void *ctx, PetscReal *sol) { 2373d525116cSMatthew G. Knepley SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "This method will not work without MPFR. Reconfigure using --download-mpfr --download-gmp"); 2374d525116cSMatthew G. Knepley } 237529f144ccSMatthew G. Knepley #endif 237629f144ccSMatthew G. Knepley 23772df84da0SMatthew G. Knepley /*@ 23782df84da0SMatthew G. Knepley PetscDTTensorQuadratureCreate - create the tensor product quadrature from two lower-dimensional quadratures 23792df84da0SMatthew G. Knepley 23802df84da0SMatthew G. Knepley Not Collective 23812df84da0SMatthew G. Knepley 23822df84da0SMatthew G. Knepley Input Parameters: 23832df84da0SMatthew G. Knepley + q1 - The first quadrature 23842df84da0SMatthew G. Knepley - q2 - The second quadrature 23852df84da0SMatthew G. Knepley 23862df84da0SMatthew G. Knepley Output Parameter: 23872df84da0SMatthew G. Knepley . q - A PetscQuadrature object 23882df84da0SMatthew G. Knepley 23892df84da0SMatthew G. Knepley Level: intermediate 23902df84da0SMatthew G. Knepley 2391db781477SPatrick Sanan .seealso: `PetscDTGaussTensorQuadrature()` 23922df84da0SMatthew G. Knepley @*/ 23939371c9d4SSatish Balay PetscErrorCode PetscDTTensorQuadratureCreate(PetscQuadrature q1, PetscQuadrature q2, PetscQuadrature *q) { 23942df84da0SMatthew G. Knepley const PetscReal *x1, *w1, *x2, *w2; 23952df84da0SMatthew G. Knepley PetscReal *x, *w; 23962df84da0SMatthew G. Knepley PetscInt dim1, Nc1, Np1, order1, qa, d1; 23972df84da0SMatthew G. Knepley PetscInt dim2, Nc2, Np2, order2, qb, d2; 23982df84da0SMatthew G. Knepley PetscInt dim, Nc, Np, order, qc, d; 23992df84da0SMatthew G. Knepley 24002df84da0SMatthew G. Knepley PetscFunctionBegin; 24012df84da0SMatthew G. Knepley PetscValidHeaderSpecific(q1, PETSCQUADRATURE_CLASSID, 1); 24022df84da0SMatthew G. Knepley PetscValidHeaderSpecific(q2, PETSCQUADRATURE_CLASSID, 2); 24032df84da0SMatthew G. Knepley PetscValidPointer(q, 3); 24049566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetOrder(q1, &order1)); 24059566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetOrder(q2, &order2)); 24062df84da0SMatthew G. Knepley PetscCheck(order1 == order2, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Order1 %" PetscInt_FMT " != %" PetscInt_FMT " Order2", order1, order2); 24079566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(q1, &dim1, &Nc1, &Np1, &x1, &w1)); 24089566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(q2, &dim2, &Nc2, &Np2, &x2, &w2)); 24092df84da0SMatthew G. Knepley PetscCheck(Nc1 == Nc2, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "NumComp1 %" PetscInt_FMT " != %" PetscInt_FMT " NumComp2", Nc1, Nc2); 24102df84da0SMatthew G. Knepley 24112df84da0SMatthew G. Knepley dim = dim1 + dim2; 24122df84da0SMatthew G. Knepley Nc = Nc1; 24132df84da0SMatthew G. Knepley Np = Np1 * Np2; 24142df84da0SMatthew G. Knepley order = order1; 24159566063dSJacob Faibussowitsch PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, q)); 24169566063dSJacob Faibussowitsch PetscCall(PetscQuadratureSetOrder(*q, order)); 24179566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(Np * dim, &x)); 24189566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(Np, &w)); 24192df84da0SMatthew G. Knepley for (qa = 0, qc = 0; qa < Np1; ++qa) { 24202df84da0SMatthew G. Knepley for (qb = 0; qb < Np2; ++qb, ++qc) { 24219371c9d4SSatish Balay for (d1 = 0, d = 0; d1 < dim1; ++d1, ++d) { x[qc * dim + d] = x1[qa * dim1 + d1]; } 24229371c9d4SSatish Balay for (d2 = 0; d2 < dim2; ++d2, ++d) { x[qc * dim + d] = x2[qb * dim2 + d2]; } 24232df84da0SMatthew G. Knepley w[qc] = w1[qa] * w2[qb]; 24242df84da0SMatthew G. Knepley } 24252df84da0SMatthew G. Knepley } 24269566063dSJacob Faibussowitsch PetscCall(PetscQuadratureSetData(*q, dim, Nc, Np, x, w)); 24272df84da0SMatthew G. Knepley PetscFunctionReturn(0); 24282df84da0SMatthew G. Knepley } 24292df84da0SMatthew G. Knepley 2430194825f6SJed Brown /* Overwrites A. Can only handle full-rank problems with m>=n 2431194825f6SJed Brown * A in column-major format 2432194825f6SJed Brown * Ainv in row-major format 2433194825f6SJed Brown * tau has length m 2434194825f6SJed Brown * worksize must be >= max(1,n) 2435194825f6SJed Brown */ 24369371c9d4SSatish Balay static PetscErrorCode PetscDTPseudoInverseQR(PetscInt m, PetscInt mstride, PetscInt n, PetscReal *A_in, PetscReal *Ainv_out, PetscScalar *tau, PetscInt worksize, PetscScalar *work) { 2437194825f6SJed Brown PetscBLASInt M, N, K, lda, ldb, ldwork, info; 2438194825f6SJed Brown PetscScalar *A, *Ainv, *R, *Q, Alpha; 2439194825f6SJed Brown 2440194825f6SJed Brown PetscFunctionBegin; 2441194825f6SJed Brown #if defined(PETSC_USE_COMPLEX) 2442194825f6SJed Brown { 2443194825f6SJed Brown PetscInt i, j; 24449566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(m * n, &A, m * n, &Ainv)); 2445194825f6SJed Brown for (j = 0; j < n; j++) { 2446194825f6SJed Brown for (i = 0; i < m; i++) A[i + m * j] = A_in[i + mstride * j]; 2447194825f6SJed Brown } 2448194825f6SJed Brown mstride = m; 2449194825f6SJed Brown } 2450194825f6SJed Brown #else 2451194825f6SJed Brown A = A_in; 2452194825f6SJed Brown Ainv = Ainv_out; 2453194825f6SJed Brown #endif 2454194825f6SJed Brown 24559566063dSJacob Faibussowitsch PetscCall(PetscBLASIntCast(m, &M)); 24569566063dSJacob Faibussowitsch PetscCall(PetscBLASIntCast(n, &N)); 24579566063dSJacob Faibussowitsch PetscCall(PetscBLASIntCast(mstride, &lda)); 24589566063dSJacob Faibussowitsch PetscCall(PetscBLASIntCast(worksize, &ldwork)); 24599566063dSJacob Faibussowitsch PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF)); 2460792fecdfSBarry Smith PetscCallBLAS("LAPACKgeqrf", LAPACKgeqrf_(&M, &N, A, &lda, tau, work, &ldwork, &info)); 24619566063dSJacob Faibussowitsch PetscCall(PetscFPTrapPop()); 246228b400f6SJacob Faibussowitsch PetscCheck(!info, PETSC_COMM_SELF, PETSC_ERR_LIB, "xGEQRF error"); 2463194825f6SJed Brown R = A; /* Upper triangular part of A now contains R, the rest contains the elementary reflectors */ 2464194825f6SJed Brown 2465194825f6SJed Brown /* Extract an explicit representation of Q */ 2466194825f6SJed Brown Q = Ainv; 24679566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(Q, A, mstride * n)); 2468194825f6SJed Brown K = N; /* full rank */ 2469792fecdfSBarry Smith PetscCallBLAS("LAPACKorgqr", LAPACKorgqr_(&M, &N, &K, Q, &lda, tau, work, &ldwork, &info)); 247028b400f6SJacob Faibussowitsch PetscCheck(!info, PETSC_COMM_SELF, PETSC_ERR_LIB, "xORGQR/xUNGQR error"); 2471194825f6SJed Brown 2472194825f6SJed Brown /* Compute A^{-T} = (R^{-1} Q^T)^T = Q R^{-T} */ 2473194825f6SJed Brown Alpha = 1.0; 2474194825f6SJed Brown ldb = lda; 2475792fecdfSBarry Smith PetscCallBLAS("BLAStrsm", BLAStrsm_("Right", "Upper", "ConjugateTranspose", "NotUnitTriangular", &M, &N, &Alpha, R, &lda, Q, &ldb)); 2476194825f6SJed Brown /* Ainv is Q, overwritten with inverse */ 2477194825f6SJed Brown 2478194825f6SJed Brown #if defined(PETSC_USE_COMPLEX) 2479194825f6SJed Brown { 2480194825f6SJed Brown PetscInt i; 2481194825f6SJed Brown for (i = 0; i < m * n; i++) Ainv_out[i] = PetscRealPart(Ainv[i]); 24829566063dSJacob Faibussowitsch PetscCall(PetscFree2(A, Ainv)); 2483194825f6SJed Brown } 2484194825f6SJed Brown #endif 2485194825f6SJed Brown PetscFunctionReturn(0); 2486194825f6SJed Brown } 2487194825f6SJed Brown 2488194825f6SJed Brown /* Computes integral of L_p' over intervals {(x0,x1),(x1,x2),...} */ 24899371c9d4SSatish Balay static PetscErrorCode PetscDTLegendreIntegrate(PetscInt ninterval, const PetscReal *x, PetscInt ndegree, const PetscInt *degrees, PetscBool Transpose, PetscReal *B) { 2490194825f6SJed Brown PetscReal *Bv; 2491194825f6SJed Brown PetscInt i, j; 2492194825f6SJed Brown 2493194825f6SJed Brown PetscFunctionBegin; 24949566063dSJacob Faibussowitsch PetscCall(PetscMalloc1((ninterval + 1) * ndegree, &Bv)); 2495194825f6SJed Brown /* Point evaluation of L_p on all the source vertices */ 24969566063dSJacob Faibussowitsch PetscCall(PetscDTLegendreEval(ninterval + 1, x, ndegree, degrees, Bv, NULL, NULL)); 2497194825f6SJed Brown /* Integral over each interval: \int_a^b L_p' = L_p(b)-L_p(a) */ 2498194825f6SJed Brown for (i = 0; i < ninterval; i++) { 2499194825f6SJed Brown for (j = 0; j < ndegree; j++) { 2500194825f6SJed Brown if (Transpose) B[i + ninterval * j] = Bv[(i + 1) * ndegree + j] - Bv[i * ndegree + j]; 2501194825f6SJed Brown else B[i * ndegree + j] = Bv[(i + 1) * ndegree + j] - Bv[i * ndegree + j]; 2502194825f6SJed Brown } 2503194825f6SJed Brown } 25049566063dSJacob Faibussowitsch PetscCall(PetscFree(Bv)); 2505194825f6SJed Brown PetscFunctionReturn(0); 2506194825f6SJed Brown } 2507194825f6SJed Brown 2508194825f6SJed Brown /*@ 2509194825f6SJed Brown PetscDTReconstructPoly - create matrix representing polynomial reconstruction using cell intervals and evaluation at target intervals 2510194825f6SJed Brown 2511194825f6SJed Brown Not Collective 2512194825f6SJed Brown 25134165533cSJose E. Roman Input Parameters: 2514194825f6SJed Brown + degree - degree of reconstruction polynomial 2515194825f6SJed Brown . nsource - number of source intervals 2516194825f6SJed Brown . sourcex - sorted coordinates of source cell boundaries (length nsource+1) 2517194825f6SJed Brown . ntarget - number of target intervals 2518194825f6SJed Brown - targetx - sorted coordinates of target cell boundaries (length ntarget+1) 2519194825f6SJed Brown 25204165533cSJose E. Roman Output Parameter: 2521194825f6SJed Brown . R - reconstruction matrix, utarget = sum_s R[t*nsource+s] * usource[s] 2522194825f6SJed Brown 2523194825f6SJed Brown Level: advanced 2524194825f6SJed Brown 2525db781477SPatrick Sanan .seealso: `PetscDTLegendreEval()` 2526194825f6SJed Brown @*/ 25279371c9d4SSatish Balay PetscErrorCode PetscDTReconstructPoly(PetscInt degree, PetscInt nsource, const PetscReal *sourcex, PetscInt ntarget, const PetscReal *targetx, PetscReal *R) { 2528194825f6SJed Brown PetscInt i, j, k, *bdegrees, worksize; 2529194825f6SJed Brown PetscReal xmin, xmax, center, hscale, *sourcey, *targety, *Bsource, *Bsinv, *Btarget; 2530194825f6SJed Brown PetscScalar *tau, *work; 2531194825f6SJed Brown 2532194825f6SJed Brown PetscFunctionBegin; 2533194825f6SJed Brown PetscValidRealPointer(sourcex, 3); 2534194825f6SJed Brown PetscValidRealPointer(targetx, 5); 2535194825f6SJed Brown PetscValidRealPointer(R, 6); 253663a3b9bcSJacob Faibussowitsch PetscCheck(degree < nsource, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Reconstruction degree %" PetscInt_FMT " must be less than number of source intervals %" PetscInt_FMT, degree, nsource); 253776bd3646SJed Brown if (PetscDefined(USE_DEBUG)) { 25389371c9d4SSatish Balay for (i = 0; i < nsource; i++) { PetscCheck(sourcex[i] < sourcex[i + 1], PETSC_COMM_SELF, PETSC_ERR_ARG_CORRUPT, "Source interval %" PetscInt_FMT " has negative orientation (%g,%g)", i, (double)sourcex[i], (double)sourcex[i + 1]); } 25399371c9d4SSatish Balay for (i = 0; i < ntarget; i++) { PetscCheck(targetx[i] < targetx[i + 1], PETSC_COMM_SELF, PETSC_ERR_ARG_CORRUPT, "Target interval %" PetscInt_FMT " has negative orientation (%g,%g)", i, (double)targetx[i], (double)targetx[i + 1]); } 254076bd3646SJed Brown } 2541194825f6SJed Brown xmin = PetscMin(sourcex[0], targetx[0]); 2542194825f6SJed Brown xmax = PetscMax(sourcex[nsource], targetx[ntarget]); 2543194825f6SJed Brown center = (xmin + xmax) / 2; 2544194825f6SJed Brown hscale = (xmax - xmin) / 2; 2545194825f6SJed Brown worksize = nsource; 25469566063dSJacob Faibussowitsch PetscCall(PetscMalloc4(degree + 1, &bdegrees, nsource + 1, &sourcey, nsource * (degree + 1), &Bsource, worksize, &work)); 25479566063dSJacob Faibussowitsch PetscCall(PetscMalloc4(nsource, &tau, nsource * (degree + 1), &Bsinv, ntarget + 1, &targety, ntarget * (degree + 1), &Btarget)); 2548194825f6SJed Brown for (i = 0; i <= nsource; i++) sourcey[i] = (sourcex[i] - center) / hscale; 2549194825f6SJed Brown for (i = 0; i <= degree; i++) bdegrees[i] = i + 1; 25509566063dSJacob Faibussowitsch PetscCall(PetscDTLegendreIntegrate(nsource, sourcey, degree + 1, bdegrees, PETSC_TRUE, Bsource)); 25519566063dSJacob Faibussowitsch PetscCall(PetscDTPseudoInverseQR(nsource, nsource, degree + 1, Bsource, Bsinv, tau, nsource, work)); 2552194825f6SJed Brown for (i = 0; i <= ntarget; i++) targety[i] = (targetx[i] - center) / hscale; 25539566063dSJacob Faibussowitsch PetscCall(PetscDTLegendreIntegrate(ntarget, targety, degree + 1, bdegrees, PETSC_FALSE, Btarget)); 2554194825f6SJed Brown for (i = 0; i < ntarget; i++) { 2555194825f6SJed Brown PetscReal rowsum = 0; 2556194825f6SJed Brown for (j = 0; j < nsource; j++) { 2557194825f6SJed Brown PetscReal sum = 0; 25589371c9d4SSatish Balay for (k = 0; k < degree + 1; k++) { sum += Btarget[i * (degree + 1) + k] * Bsinv[k * nsource + j]; } 2559194825f6SJed Brown R[i * nsource + j] = sum; 2560194825f6SJed Brown rowsum += sum; 2561194825f6SJed Brown } 2562194825f6SJed Brown for (j = 0; j < nsource; j++) R[i * nsource + j] /= rowsum; /* normalize each row */ 2563194825f6SJed Brown } 25649566063dSJacob Faibussowitsch PetscCall(PetscFree4(bdegrees, sourcey, Bsource, work)); 25659566063dSJacob Faibussowitsch PetscCall(PetscFree4(tau, Bsinv, targety, Btarget)); 2566194825f6SJed Brown PetscFunctionReturn(0); 2567194825f6SJed Brown } 2568916e780bShannah_mairs 2569916e780bShannah_mairs /*@C 2570916e780bShannah_mairs PetscGaussLobattoLegendreIntegrate - Compute the L2 integral of a function on the GLL points 2571916e780bShannah_mairs 2572916e780bShannah_mairs Not Collective 2573916e780bShannah_mairs 2574d8d19677SJose E. Roman Input Parameters: 2575916e780bShannah_mairs + n - the number of GLL nodes 2576916e780bShannah_mairs . nodes - the GLL nodes 2577916e780bShannah_mairs . weights - the GLL weights 2578f0fc11ceSJed Brown - f - the function values at the nodes 2579916e780bShannah_mairs 2580916e780bShannah_mairs Output Parameter: 2581916e780bShannah_mairs . in - the value of the integral 2582916e780bShannah_mairs 2583916e780bShannah_mairs Level: beginner 2584916e780bShannah_mairs 2585db781477SPatrick Sanan .seealso: `PetscDTGaussLobattoLegendreQuadrature()` 2586916e780bShannah_mairs 2587916e780bShannah_mairs @*/ 25889371c9d4SSatish Balay PetscErrorCode PetscGaussLobattoLegendreIntegrate(PetscInt n, PetscReal *nodes, PetscReal *weights, const PetscReal *f, PetscReal *in) { 2589916e780bShannah_mairs PetscInt i; 2590916e780bShannah_mairs 2591916e780bShannah_mairs PetscFunctionBegin; 2592916e780bShannah_mairs *in = 0.; 25939371c9d4SSatish Balay for (i = 0; i < n; i++) { *in += f[i] * f[i] * weights[i]; } 2594916e780bShannah_mairs PetscFunctionReturn(0); 2595916e780bShannah_mairs } 2596916e780bShannah_mairs 2597916e780bShannah_mairs /*@C 2598916e780bShannah_mairs PetscGaussLobattoLegendreElementLaplacianCreate - computes the Laplacian for a single 1d GLL element 2599916e780bShannah_mairs 2600916e780bShannah_mairs Not Collective 2601916e780bShannah_mairs 2602d8d19677SJose E. Roman Input Parameters: 2603916e780bShannah_mairs + n - the number of GLL nodes 2604916e780bShannah_mairs . nodes - the GLL nodes 2605f0fc11ceSJed Brown - weights - the GLL weights 2606916e780bShannah_mairs 2607916e780bShannah_mairs Output Parameter: 2608916e780bShannah_mairs . A - the stiffness element 2609916e780bShannah_mairs 2610916e780bShannah_mairs Level: beginner 2611916e780bShannah_mairs 2612916e780bShannah_mairs Notes: 2613916e780bShannah_mairs Destroy this with PetscGaussLobattoLegendreElementLaplacianDestroy() 2614916e780bShannah_mairs 2615916e780bShannah_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) 2616916e780bShannah_mairs 2617db781477SPatrick Sanan .seealso: `PetscDTGaussLobattoLegendreQuadrature()`, `PetscGaussLobattoLegendreElementLaplacianDestroy()` 2618916e780bShannah_mairs 2619916e780bShannah_mairs @*/ 26209371c9d4SSatish Balay PetscErrorCode PetscGaussLobattoLegendreElementLaplacianCreate(PetscInt n, PetscReal *nodes, PetscReal *weights, PetscReal ***AA) { 2621916e780bShannah_mairs PetscReal **A; 2622916e780bShannah_mairs const PetscReal *gllnodes = nodes; 2623916e780bShannah_mairs const PetscInt p = n - 1; 2624916e780bShannah_mairs PetscReal z0, z1, z2 = -1, x, Lpj, Lpr; 2625916e780bShannah_mairs PetscInt i, j, nn, r; 2626916e780bShannah_mairs 2627916e780bShannah_mairs PetscFunctionBegin; 26289566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(n, &A)); 26299566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(n * n, &A[0])); 2630916e780bShannah_mairs for (i = 1; i < n; i++) A[i] = A[i - 1] + n; 2631916e780bShannah_mairs 2632916e780bShannah_mairs for (j = 1; j < p; j++) { 2633916e780bShannah_mairs x = gllnodes[j]; 2634916e780bShannah_mairs z0 = 1.; 2635916e780bShannah_mairs z1 = x; 2636916e780bShannah_mairs for (nn = 1; nn < p; nn++) { 2637916e780bShannah_mairs z2 = x * z1 * (2. * ((PetscReal)nn) + 1.) / (((PetscReal)nn) + 1.) - z0 * (((PetscReal)nn) / (((PetscReal)nn) + 1.)); 2638916e780bShannah_mairs z0 = z1; 2639916e780bShannah_mairs z1 = z2; 2640916e780bShannah_mairs } 2641916e780bShannah_mairs Lpj = z2; 2642916e780bShannah_mairs for (r = 1; r < p; r++) { 2643916e780bShannah_mairs if (r == j) { 2644916e780bShannah_mairs A[j][j] = 2. / (3. * (1. - gllnodes[j] * gllnodes[j]) * Lpj * Lpj); 2645916e780bShannah_mairs } else { 2646916e780bShannah_mairs x = gllnodes[r]; 2647916e780bShannah_mairs z0 = 1.; 2648916e780bShannah_mairs z1 = x; 2649916e780bShannah_mairs for (nn = 1; nn < p; nn++) { 2650916e780bShannah_mairs z2 = x * z1 * (2. * ((PetscReal)nn) + 1.) / (((PetscReal)nn) + 1.) - z0 * (((PetscReal)nn) / (((PetscReal)nn) + 1.)); 2651916e780bShannah_mairs z0 = z1; 2652916e780bShannah_mairs z1 = z2; 2653916e780bShannah_mairs } 2654916e780bShannah_mairs Lpr = z2; 2655916e780bShannah_mairs A[r][j] = 4. / (((PetscReal)p) * (((PetscReal)p) + 1.) * Lpj * Lpr * (gllnodes[j] - gllnodes[r]) * (gllnodes[j] - gllnodes[r])); 2656916e780bShannah_mairs } 2657916e780bShannah_mairs } 2658916e780bShannah_mairs } 2659916e780bShannah_mairs for (j = 1; j < p + 1; j++) { 2660916e780bShannah_mairs x = gllnodes[j]; 2661916e780bShannah_mairs z0 = 1.; 2662916e780bShannah_mairs z1 = x; 2663916e780bShannah_mairs for (nn = 1; nn < p; nn++) { 2664916e780bShannah_mairs z2 = x * z1 * (2. * ((PetscReal)nn) + 1.) / (((PetscReal)nn) + 1.) - z0 * (((PetscReal)nn) / (((PetscReal)nn) + 1.)); 2665916e780bShannah_mairs z0 = z1; 2666916e780bShannah_mairs z1 = z2; 2667916e780bShannah_mairs } 2668916e780bShannah_mairs Lpj = z2; 2669916e780bShannah_mairs A[j][0] = 4. * PetscPowRealInt(-1., p) / (((PetscReal)p) * (((PetscReal)p) + 1.) * Lpj * (1. + gllnodes[j]) * (1. + gllnodes[j])); 2670916e780bShannah_mairs A[0][j] = A[j][0]; 2671916e780bShannah_mairs } 2672916e780bShannah_mairs for (j = 0; j < p; j++) { 2673916e780bShannah_mairs x = gllnodes[j]; 2674916e780bShannah_mairs z0 = 1.; 2675916e780bShannah_mairs z1 = x; 2676916e780bShannah_mairs for (nn = 1; nn < p; nn++) { 2677916e780bShannah_mairs z2 = x * z1 * (2. * ((PetscReal)nn) + 1.) / (((PetscReal)nn) + 1.) - z0 * (((PetscReal)nn) / (((PetscReal)nn) + 1.)); 2678916e780bShannah_mairs z0 = z1; 2679916e780bShannah_mairs z1 = z2; 2680916e780bShannah_mairs } 2681916e780bShannah_mairs Lpj = z2; 2682916e780bShannah_mairs 2683916e780bShannah_mairs A[p][j] = 4. / (((PetscReal)p) * (((PetscReal)p) + 1.) * Lpj * (1. - gllnodes[j]) * (1. - gllnodes[j])); 2684916e780bShannah_mairs A[j][p] = A[p][j]; 2685916e780bShannah_mairs } 2686916e780bShannah_mairs A[0][0] = 0.5 + (((PetscReal)p) * (((PetscReal)p) + 1.) - 2.) / 6.; 2687916e780bShannah_mairs A[p][p] = A[0][0]; 2688916e780bShannah_mairs *AA = A; 2689916e780bShannah_mairs PetscFunctionReturn(0); 2690916e780bShannah_mairs } 2691916e780bShannah_mairs 2692916e780bShannah_mairs /*@C 2693916e780bShannah_mairs PetscGaussLobattoLegendreElementLaplacianDestroy - frees the Laplacian for a single 1d GLL element 2694916e780bShannah_mairs 2695916e780bShannah_mairs Not Collective 2696916e780bShannah_mairs 2697d8d19677SJose E. Roman Input Parameters: 2698916e780bShannah_mairs + n - the number of GLL nodes 2699916e780bShannah_mairs . nodes - the GLL nodes 2700916e780bShannah_mairs . weights - the GLL weightss 2701916e780bShannah_mairs - A - the stiffness element 2702916e780bShannah_mairs 2703916e780bShannah_mairs Level: beginner 2704916e780bShannah_mairs 2705db781477SPatrick Sanan .seealso: `PetscDTGaussLobattoLegendreQuadrature()`, `PetscGaussLobattoLegendreElementLaplacianCreate()` 2706916e780bShannah_mairs 2707916e780bShannah_mairs @*/ 27089371c9d4SSatish Balay PetscErrorCode PetscGaussLobattoLegendreElementLaplacianDestroy(PetscInt n, PetscReal *nodes, PetscReal *weights, PetscReal ***AA) { 2709916e780bShannah_mairs PetscFunctionBegin; 27109566063dSJacob Faibussowitsch PetscCall(PetscFree((*AA)[0])); 27119566063dSJacob Faibussowitsch PetscCall(PetscFree(*AA)); 2712916e780bShannah_mairs *AA = NULL; 2713916e780bShannah_mairs PetscFunctionReturn(0); 2714916e780bShannah_mairs } 2715916e780bShannah_mairs 2716916e780bShannah_mairs /*@C 2717916e780bShannah_mairs PetscGaussLobattoLegendreElementGradientCreate - computes the gradient for a single 1d GLL element 2718916e780bShannah_mairs 2719916e780bShannah_mairs Not Collective 2720916e780bShannah_mairs 2721916e780bShannah_mairs Input Parameter: 2722916e780bShannah_mairs + n - the number of GLL nodes 2723916e780bShannah_mairs . nodes - the GLL nodes 2724916e780bShannah_mairs . weights - the GLL weights 2725916e780bShannah_mairs 2726d8d19677SJose E. Roman Output Parameters: 2727916e780bShannah_mairs . AA - the stiffness element 2728916e780bShannah_mairs - AAT - the transpose of AA (pass in NULL if you do not need this array) 2729916e780bShannah_mairs 2730916e780bShannah_mairs Level: beginner 2731916e780bShannah_mairs 2732916e780bShannah_mairs Notes: 2733916e780bShannah_mairs Destroy this with PetscGaussLobattoLegendreElementGradientDestroy() 2734916e780bShannah_mairs 2735916e780bShannah_mairs You can access entries in these arrays with AA[i][j] but in memory it is stored in contiguous memory, row oriented 2736916e780bShannah_mairs 2737db781477SPatrick Sanan .seealso: `PetscDTGaussLobattoLegendreQuadrature()`, `PetscGaussLobattoLegendreElementLaplacianDestroy()` 2738916e780bShannah_mairs 2739916e780bShannah_mairs @*/ 27409371c9d4SSatish Balay PetscErrorCode PetscGaussLobattoLegendreElementGradientCreate(PetscInt n, PetscReal *nodes, PetscReal *weights, PetscReal ***AA, PetscReal ***AAT) { 2741916e780bShannah_mairs PetscReal **A, **AT = NULL; 2742916e780bShannah_mairs const PetscReal *gllnodes = nodes; 2743916e780bShannah_mairs const PetscInt p = n - 1; 2744e6a796c3SToby Isaac PetscReal Li, Lj, d0; 2745916e780bShannah_mairs PetscInt i, j; 2746916e780bShannah_mairs 2747916e780bShannah_mairs PetscFunctionBegin; 27489566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(n, &A)); 27499566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(n * n, &A[0])); 2750916e780bShannah_mairs for (i = 1; i < n; i++) A[i] = A[i - 1] + n; 2751916e780bShannah_mairs 2752916e780bShannah_mairs if (AAT) { 27539566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(n, &AT)); 27549566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(n * n, &AT[0])); 2755916e780bShannah_mairs for (i = 1; i < n; i++) AT[i] = AT[i - 1] + n; 2756916e780bShannah_mairs } 2757916e780bShannah_mairs 2758916e780bShannah_mairs if (n == 1) { A[0][0] = 0.; } 2759916e780bShannah_mairs d0 = (PetscReal)p * ((PetscReal)p + 1.) / 4.; 2760916e780bShannah_mairs for (i = 0; i < n; i++) { 2761916e780bShannah_mairs for (j = 0; j < n; j++) { 2762916e780bShannah_mairs A[i][j] = 0.; 27639566063dSJacob Faibussowitsch PetscCall(PetscDTComputeJacobi(0., 0., p, gllnodes[i], &Li)); 27649566063dSJacob Faibussowitsch PetscCall(PetscDTComputeJacobi(0., 0., p, gllnodes[j], &Lj)); 2765916e780bShannah_mairs if (i != j) A[i][j] = Li / (Lj * (gllnodes[i] - gllnodes[j])); 2766916e780bShannah_mairs if ((j == i) && (i == 0)) A[i][j] = -d0; 2767916e780bShannah_mairs if (j == i && i == p) A[i][j] = d0; 2768916e780bShannah_mairs if (AT) AT[j][i] = A[i][j]; 2769916e780bShannah_mairs } 2770916e780bShannah_mairs } 2771916e780bShannah_mairs if (AAT) *AAT = AT; 2772916e780bShannah_mairs *AA = A; 2773916e780bShannah_mairs PetscFunctionReturn(0); 2774916e780bShannah_mairs } 2775916e780bShannah_mairs 2776916e780bShannah_mairs /*@C 2777916e780bShannah_mairs PetscGaussLobattoLegendreElementGradientDestroy - frees the gradient for a single 1d GLL element obtained with PetscGaussLobattoLegendreElementGradientCreate() 2778916e780bShannah_mairs 2779916e780bShannah_mairs Not Collective 2780916e780bShannah_mairs 2781d8d19677SJose E. Roman Input Parameters: 2782916e780bShannah_mairs + n - the number of GLL nodes 2783916e780bShannah_mairs . nodes - the GLL nodes 2784916e780bShannah_mairs . weights - the GLL weights 2785916e780bShannah_mairs . AA - the stiffness element 2786916e780bShannah_mairs - AAT - the transpose of the element 2787916e780bShannah_mairs 2788916e780bShannah_mairs Level: beginner 2789916e780bShannah_mairs 2790db781477SPatrick Sanan .seealso: `PetscDTGaussLobattoLegendreQuadrature()`, `PetscGaussLobattoLegendreElementLaplacianCreate()`, `PetscGaussLobattoLegendreElementAdvectionCreate()` 2791916e780bShannah_mairs 2792916e780bShannah_mairs @*/ 27939371c9d4SSatish Balay PetscErrorCode PetscGaussLobattoLegendreElementGradientDestroy(PetscInt n, PetscReal *nodes, PetscReal *weights, PetscReal ***AA, PetscReal ***AAT) { 2794916e780bShannah_mairs PetscFunctionBegin; 27959566063dSJacob Faibussowitsch PetscCall(PetscFree((*AA)[0])); 27969566063dSJacob Faibussowitsch PetscCall(PetscFree(*AA)); 2797916e780bShannah_mairs *AA = NULL; 2798916e780bShannah_mairs if (*AAT) { 27999566063dSJacob Faibussowitsch PetscCall(PetscFree((*AAT)[0])); 28009566063dSJacob Faibussowitsch PetscCall(PetscFree(*AAT)); 2801916e780bShannah_mairs *AAT = NULL; 2802916e780bShannah_mairs } 2803916e780bShannah_mairs PetscFunctionReturn(0); 2804916e780bShannah_mairs } 2805916e780bShannah_mairs 2806916e780bShannah_mairs /*@C 2807916e780bShannah_mairs PetscGaussLobattoLegendreElementAdvectionCreate - computes the advection operator for a single 1d GLL element 2808916e780bShannah_mairs 2809916e780bShannah_mairs Not Collective 2810916e780bShannah_mairs 2811d8d19677SJose E. Roman Input Parameters: 2812916e780bShannah_mairs + n - the number of GLL nodes 2813916e780bShannah_mairs . nodes - the GLL nodes 2814f0fc11ceSJed Brown - weights - the GLL weightss 2815916e780bShannah_mairs 2816916e780bShannah_mairs Output Parameter: 2817916e780bShannah_mairs . AA - the stiffness element 2818916e780bShannah_mairs 2819916e780bShannah_mairs Level: beginner 2820916e780bShannah_mairs 2821916e780bShannah_mairs Notes: 2822916e780bShannah_mairs Destroy this with PetscGaussLobattoLegendreElementAdvectionDestroy() 2823916e780bShannah_mairs 2824916e780bShannah_mairs This is the same as the Gradient operator multiplied by the diagonal mass matrix 2825916e780bShannah_mairs 2826916e780bShannah_mairs You can access entries in this array with AA[i][j] but in memory it is stored in contiguous memory, row oriented 2827916e780bShannah_mairs 2828db781477SPatrick Sanan .seealso: `PetscDTGaussLobattoLegendreQuadrature()`, `PetscGaussLobattoLegendreElementLaplacianCreate()`, `PetscGaussLobattoLegendreElementAdvectionDestroy()` 2829916e780bShannah_mairs 2830916e780bShannah_mairs @*/ 28319371c9d4SSatish Balay PetscErrorCode PetscGaussLobattoLegendreElementAdvectionCreate(PetscInt n, PetscReal *nodes, PetscReal *weights, PetscReal ***AA) { 2832916e780bShannah_mairs PetscReal **D; 2833916e780bShannah_mairs const PetscReal *gllweights = weights; 2834916e780bShannah_mairs const PetscInt glln = n; 2835916e780bShannah_mairs PetscInt i, j; 2836916e780bShannah_mairs 2837916e780bShannah_mairs PetscFunctionBegin; 28389566063dSJacob Faibussowitsch PetscCall(PetscGaussLobattoLegendreElementGradientCreate(n, nodes, weights, &D, NULL)); 2839916e780bShannah_mairs for (i = 0; i < glln; i++) { 28409371c9d4SSatish Balay for (j = 0; j < glln; j++) { D[i][j] = gllweights[i] * D[i][j]; } 2841916e780bShannah_mairs } 2842916e780bShannah_mairs *AA = D; 2843916e780bShannah_mairs PetscFunctionReturn(0); 2844916e780bShannah_mairs } 2845916e780bShannah_mairs 2846916e780bShannah_mairs /*@C 2847916e780bShannah_mairs PetscGaussLobattoLegendreElementAdvectionDestroy - frees the advection stiffness for a single 1d GLL element 2848916e780bShannah_mairs 2849916e780bShannah_mairs Not Collective 2850916e780bShannah_mairs 2851d8d19677SJose E. Roman Input Parameters: 2852916e780bShannah_mairs + n - the number of GLL nodes 2853916e780bShannah_mairs . nodes - the GLL nodes 2854916e780bShannah_mairs . weights - the GLL weights 2855916e780bShannah_mairs - A - advection 2856916e780bShannah_mairs 2857916e780bShannah_mairs Level: beginner 2858916e780bShannah_mairs 2859db781477SPatrick Sanan .seealso: `PetscDTGaussLobattoLegendreQuadrature()`, `PetscGaussLobattoLegendreElementAdvectionCreate()` 2860916e780bShannah_mairs 2861916e780bShannah_mairs @*/ 28629371c9d4SSatish Balay PetscErrorCode PetscGaussLobattoLegendreElementAdvectionDestroy(PetscInt n, PetscReal *nodes, PetscReal *weights, PetscReal ***AA) { 2863916e780bShannah_mairs PetscFunctionBegin; 28649566063dSJacob Faibussowitsch PetscCall(PetscFree((*AA)[0])); 28659566063dSJacob Faibussowitsch PetscCall(PetscFree(*AA)); 2866916e780bShannah_mairs *AA = NULL; 2867916e780bShannah_mairs PetscFunctionReturn(0); 2868916e780bShannah_mairs } 2869916e780bShannah_mairs 28709371c9d4SSatish Balay PetscErrorCode PetscGaussLobattoLegendreElementMassCreate(PetscInt n, PetscReal *nodes, PetscReal *weights, PetscReal ***AA) { 2871916e780bShannah_mairs PetscReal **A; 2872916e780bShannah_mairs const PetscReal *gllweights = weights; 2873916e780bShannah_mairs const PetscInt glln = n; 2874916e780bShannah_mairs PetscInt i, j; 2875916e780bShannah_mairs 2876916e780bShannah_mairs PetscFunctionBegin; 28779566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(glln, &A)); 28789566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(glln * glln, &A[0])); 2879916e780bShannah_mairs for (i = 1; i < glln; i++) A[i] = A[i - 1] + glln; 2880916e780bShannah_mairs if (glln == 1) { A[0][0] = 0.; } 2881916e780bShannah_mairs for (i = 0; i < glln; i++) { 2882916e780bShannah_mairs for (j = 0; j < glln; j++) { 2883916e780bShannah_mairs A[i][j] = 0.; 2884916e780bShannah_mairs if (j == i) A[i][j] = gllweights[i]; 2885916e780bShannah_mairs } 2886916e780bShannah_mairs } 2887916e780bShannah_mairs *AA = A; 2888916e780bShannah_mairs PetscFunctionReturn(0); 2889916e780bShannah_mairs } 2890916e780bShannah_mairs 28919371c9d4SSatish Balay PetscErrorCode PetscGaussLobattoLegendreElementMassDestroy(PetscInt n, PetscReal *nodes, PetscReal *weights, PetscReal ***AA) { 2892916e780bShannah_mairs PetscFunctionBegin; 28939566063dSJacob Faibussowitsch PetscCall(PetscFree((*AA)[0])); 28949566063dSJacob Faibussowitsch PetscCall(PetscFree(*AA)); 2895916e780bShannah_mairs *AA = NULL; 2896916e780bShannah_mairs PetscFunctionReturn(0); 2897916e780bShannah_mairs } 2898d4afb720SToby Isaac 2899d4afb720SToby Isaac /*@ 2900d4afb720SToby Isaac PetscDTIndexToBary - convert an index into a barycentric coordinate. 2901d4afb720SToby Isaac 2902d4afb720SToby Isaac Input Parameters: 2903d4afb720SToby 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) 2904d4afb720SToby Isaac . sum - the value that the sum of the barycentric coordinates (which will be non-negative integers) should sum to 2905d4afb720SToby Isaac - index - the index to convert: should be >= 0 and < Binomial(len - 1 + sum, sum) 2906d4afb720SToby Isaac 2907d4afb720SToby Isaac Output Parameter: 2908d4afb720SToby Isaac . coord - will be filled with the barycentric coordinate 2909d4afb720SToby Isaac 2910d4afb720SToby Isaac Level: beginner 2911d4afb720SToby Isaac 2912d4afb720SToby Isaac Note: the indices map to barycentric coordinates in lexicographic order, where the first index is the 2913d4afb720SToby Isaac least significant and the last index is the most significant. 2914d4afb720SToby Isaac 2915db781477SPatrick Sanan .seealso: `PetscDTBaryToIndex()` 2916d4afb720SToby Isaac @*/ 29179371c9d4SSatish Balay PetscErrorCode PetscDTIndexToBary(PetscInt len, PetscInt sum, PetscInt index, PetscInt coord[]) { 2918d4afb720SToby Isaac PetscInt c, d, s, total, subtotal, nexttotal; 2919d4afb720SToby Isaac 2920d4afb720SToby Isaac PetscFunctionBeginHot; 292108401ef6SPierre Jolivet PetscCheck(len >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "length must be non-negative"); 292208401ef6SPierre Jolivet PetscCheck(index >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "index must be non-negative"); 2923d4afb720SToby Isaac if (!len) { 2924d4afb720SToby Isaac if (!sum && !index) PetscFunctionReturn(0); 2925d4afb720SToby Isaac SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid index or sum for length 0 barycentric coordinate"); 2926d4afb720SToby Isaac } 2927d4afb720SToby Isaac for (c = 1, total = 1; c <= len; c++) { 2928d4afb720SToby Isaac /* total is the number of ways to have a tuple of length c with sum */ 2929d4afb720SToby Isaac if (index < total) break; 2930d4afb720SToby Isaac total = (total * (sum + c)) / c; 2931d4afb720SToby Isaac } 293208401ef6SPierre Jolivet PetscCheck(c <= len, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "index out of range"); 2933d4afb720SToby Isaac for (d = c; d < len; d++) coord[d] = 0; 2934d4afb720SToby Isaac for (s = 0, subtotal = 1, nexttotal = 1; c > 0;) { 2935d4afb720SToby Isaac /* subtotal is the number of ways to have a tuple of length c with sum s */ 2936d4afb720SToby Isaac /* nexttotal is the number of ways to have a tuple of length c-1 with sum s */ 2937d4afb720SToby Isaac if ((index + subtotal) >= total) { 2938d4afb720SToby Isaac coord[--c] = sum - s; 2939d4afb720SToby Isaac index -= (total - subtotal); 2940d4afb720SToby Isaac sum = s; 2941d4afb720SToby Isaac total = nexttotal; 2942d4afb720SToby Isaac subtotal = 1; 2943d4afb720SToby Isaac nexttotal = 1; 2944d4afb720SToby Isaac s = 0; 2945d4afb720SToby Isaac } else { 2946d4afb720SToby Isaac subtotal = (subtotal * (c + s)) / (s + 1); 2947d4afb720SToby Isaac nexttotal = (nexttotal * (c - 1 + s)) / (s + 1); 2948d4afb720SToby Isaac s++; 2949d4afb720SToby Isaac } 2950d4afb720SToby Isaac } 2951d4afb720SToby Isaac PetscFunctionReturn(0); 2952d4afb720SToby Isaac } 2953d4afb720SToby Isaac 2954d4afb720SToby Isaac /*@ 2955d4afb720SToby Isaac PetscDTBaryToIndex - convert a barycentric coordinate to an index 2956d4afb720SToby Isaac 2957d4afb720SToby Isaac Input Parameters: 2958d4afb720SToby 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) 2959d4afb720SToby Isaac . sum - the value that the sum of the barycentric coordinates (which will be non-negative integers) should sum to 2960d4afb720SToby Isaac - coord - a barycentric coordinate with the given length and sum 2961d4afb720SToby Isaac 2962d4afb720SToby Isaac Output Parameter: 2963d4afb720SToby Isaac . index - the unique index for the coordinate, >= 0 and < Binomial(len - 1 + sum, sum) 2964d4afb720SToby Isaac 2965d4afb720SToby Isaac Level: beginner 2966d4afb720SToby Isaac 2967d4afb720SToby Isaac Note: the indices map to barycentric coordinates in lexicographic order, where the first index is the 2968d4afb720SToby Isaac least significant and the last index is the most significant. 2969d4afb720SToby Isaac 2970db781477SPatrick Sanan .seealso: `PetscDTIndexToBary` 2971d4afb720SToby Isaac @*/ 29729371c9d4SSatish Balay PetscErrorCode PetscDTBaryToIndex(PetscInt len, PetscInt sum, const PetscInt coord[], PetscInt *index) { 2973d4afb720SToby Isaac PetscInt c; 2974d4afb720SToby Isaac PetscInt i; 2975d4afb720SToby Isaac PetscInt total; 2976d4afb720SToby Isaac 2977d4afb720SToby Isaac PetscFunctionBeginHot; 297808401ef6SPierre Jolivet PetscCheck(len >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "length must be non-negative"); 2979d4afb720SToby Isaac if (!len) { 2980d4afb720SToby Isaac if (!sum) { 2981d4afb720SToby Isaac *index = 0; 2982d4afb720SToby Isaac PetscFunctionReturn(0); 2983d4afb720SToby Isaac } 2984d4afb720SToby Isaac SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid index or sum for length 0 barycentric coordinate"); 2985d4afb720SToby Isaac } 2986d4afb720SToby Isaac for (c = 1, total = 1; c < len; c++) total = (total * (sum + c)) / c; 2987d4afb720SToby Isaac i = total - 1; 2988d4afb720SToby Isaac c = len - 1; 2989d4afb720SToby Isaac sum -= coord[c]; 2990d4afb720SToby Isaac while (sum > 0) { 2991d4afb720SToby Isaac PetscInt subtotal; 2992d4afb720SToby Isaac PetscInt s; 2993d4afb720SToby Isaac 2994d4afb720SToby Isaac for (s = 1, subtotal = 1; s < sum; s++) subtotal = (subtotal * (c + s)) / s; 2995d4afb720SToby Isaac i -= subtotal; 2996d4afb720SToby Isaac sum -= coord[--c]; 2997d4afb720SToby Isaac } 2998d4afb720SToby Isaac *index = i; 2999d4afb720SToby Isaac PetscFunctionReturn(0); 3000d4afb720SToby Isaac } 3001