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 @*/ 59*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscQuadratureCreate(MPI_Comm comm, PetscQuadrature *q) 60*d71ae5a4SJacob Faibussowitsch { 6121454ff5SMatthew G. Knepley PetscFunctionBegin; 6221454ff5SMatthew G. Knepley PetscValidPointer(q, 2); 639566063dSJacob Faibussowitsch PetscCall(DMInitializePackage()); 649566063dSJacob Faibussowitsch PetscCall(PetscHeaderCreate(*q, PETSCQUADRATURE_CLASSID, "PetscQuadrature", "Quadrature", "DT", comm, PetscQuadratureDestroy, PetscQuadratureView)); 6521454ff5SMatthew G. Knepley (*q)->dim = -1; 66a6b92713SMatthew G. Knepley (*q)->Nc = 1; 67bcede257SMatthew G. Knepley (*q)->order = -1; 6821454ff5SMatthew G. Knepley (*q)->numPoints = 0; 6921454ff5SMatthew G. Knepley (*q)->points = NULL; 7021454ff5SMatthew G. Knepley (*q)->weights = NULL; 7121454ff5SMatthew G. Knepley PetscFunctionReturn(0); 7221454ff5SMatthew G. Knepley } 7321454ff5SMatthew G. Knepley 74c9638911SMatthew G. Knepley /*@ 75c9638911SMatthew G. Knepley PetscQuadratureDuplicate - Create a deep copy of the PetscQuadrature object 76c9638911SMatthew G. Knepley 77d083f849SBarry Smith Collective on q 78c9638911SMatthew G. Knepley 79c9638911SMatthew G. Knepley Input Parameter: 80c9638911SMatthew G. Knepley . q - The PetscQuadrature object 81c9638911SMatthew G. Knepley 82c9638911SMatthew G. Knepley Output Parameter: 83c9638911SMatthew G. Knepley . r - The new PetscQuadrature object 84c9638911SMatthew G. Knepley 85c9638911SMatthew G. Knepley Level: beginner 86c9638911SMatthew G. Knepley 87db781477SPatrick Sanan .seealso: `PetscQuadratureCreate()`, `PetscQuadratureDestroy()`, `PetscQuadratureGetData()` 88c9638911SMatthew G. Knepley @*/ 89*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscQuadratureDuplicate(PetscQuadrature q, PetscQuadrature *r) 90*d71ae5a4SJacob Faibussowitsch { 91a6b92713SMatthew G. Knepley PetscInt order, dim, Nc, Nq; 92c9638911SMatthew G. Knepley const PetscReal *points, *weights; 93c9638911SMatthew G. Knepley PetscReal *p, *w; 94c9638911SMatthew G. Knepley 95c9638911SMatthew G. Knepley PetscFunctionBegin; 96064a246eSJacob Faibussowitsch PetscValidPointer(q, 1); 979566063dSJacob Faibussowitsch PetscCall(PetscQuadratureCreate(PetscObjectComm((PetscObject)q), r)); 989566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetOrder(q, &order)); 999566063dSJacob Faibussowitsch PetscCall(PetscQuadratureSetOrder(*r, order)); 1009566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(q, &dim, &Nc, &Nq, &points, &weights)); 1019566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(Nq * dim, &p)); 1029566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(Nq * Nc, &w)); 1039566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(p, points, Nq * dim)); 1049566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(w, weights, Nc * Nq)); 1059566063dSJacob Faibussowitsch PetscCall(PetscQuadratureSetData(*r, dim, Nc, Nq, p, w)); 106c9638911SMatthew G. Knepley PetscFunctionReturn(0); 107c9638911SMatthew G. Knepley } 108c9638911SMatthew G. Knepley 10940d8ff71SMatthew G. Knepley /*@ 11040d8ff71SMatthew G. Knepley PetscQuadratureDestroy - Destroys a PetscQuadrature object 11140d8ff71SMatthew G. Knepley 112d083f849SBarry Smith Collective on q 11340d8ff71SMatthew G. Knepley 11440d8ff71SMatthew G. Knepley Input Parameter: 11540d8ff71SMatthew G. Knepley . q - The PetscQuadrature object 11640d8ff71SMatthew G. Knepley 11740d8ff71SMatthew G. Knepley Level: beginner 11840d8ff71SMatthew G. Knepley 119db781477SPatrick Sanan .seealso: `PetscQuadratureCreate()`, `PetscQuadratureGetData()` 12040d8ff71SMatthew G. Knepley @*/ 121*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscQuadratureDestroy(PetscQuadrature *q) 122*d71ae5a4SJacob Faibussowitsch { 123bfa639d9SMatthew G. Knepley PetscFunctionBegin; 12421454ff5SMatthew G. Knepley if (!*q) PetscFunctionReturn(0); 1252cd22861SMatthew G. Knepley PetscValidHeaderSpecific((*q), PETSCQUADRATURE_CLASSID, 1); 12621454ff5SMatthew G. Knepley if (--((PetscObject)(*q))->refct > 0) { 12721454ff5SMatthew G. Knepley *q = NULL; 12821454ff5SMatthew G. Knepley PetscFunctionReturn(0); 12921454ff5SMatthew G. Knepley } 1309566063dSJacob Faibussowitsch PetscCall(PetscFree((*q)->points)); 1319566063dSJacob Faibussowitsch PetscCall(PetscFree((*q)->weights)); 1329566063dSJacob Faibussowitsch PetscCall(PetscHeaderDestroy(q)); 13321454ff5SMatthew G. Knepley PetscFunctionReturn(0); 13421454ff5SMatthew G. Knepley } 13521454ff5SMatthew G. Knepley 136bcede257SMatthew G. Knepley /*@ 137a6b92713SMatthew G. Knepley PetscQuadratureGetOrder - Return the order of the method 138bcede257SMatthew G. Knepley 139bcede257SMatthew G. Knepley Not collective 140bcede257SMatthew G. Knepley 141bcede257SMatthew G. Knepley Input Parameter: 142bcede257SMatthew G. Knepley . q - The PetscQuadrature object 143bcede257SMatthew G. Knepley 144bcede257SMatthew G. Knepley Output Parameter: 145bcede257SMatthew G. Knepley . order - The order of the quadrature, i.e. the highest degree polynomial that is exactly integrated 146bcede257SMatthew G. Knepley 147bcede257SMatthew G. Knepley Level: intermediate 148bcede257SMatthew G. Knepley 149db781477SPatrick Sanan .seealso: `PetscQuadratureSetOrder()`, `PetscQuadratureGetData()`, `PetscQuadratureSetData()` 150bcede257SMatthew G. Knepley @*/ 151*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscQuadratureGetOrder(PetscQuadrature q, PetscInt *order) 152*d71ae5a4SJacob Faibussowitsch { 153bcede257SMatthew G. Knepley PetscFunctionBegin; 1542cd22861SMatthew G. Knepley PetscValidHeaderSpecific(q, PETSCQUADRATURE_CLASSID, 1); 155dadcf809SJacob Faibussowitsch PetscValidIntPointer(order, 2); 156bcede257SMatthew G. Knepley *order = q->order; 157bcede257SMatthew G. Knepley PetscFunctionReturn(0); 158bcede257SMatthew G. Knepley } 159bcede257SMatthew G. Knepley 160bcede257SMatthew G. Knepley /*@ 161a6b92713SMatthew G. Knepley PetscQuadratureSetOrder - Return the order of the method 162bcede257SMatthew G. Knepley 163bcede257SMatthew G. Knepley Not collective 164bcede257SMatthew G. Knepley 165bcede257SMatthew G. Knepley Input Parameters: 166bcede257SMatthew G. Knepley + q - The PetscQuadrature object 167bcede257SMatthew G. Knepley - order - The order of the quadrature, i.e. the highest degree polynomial that is exactly integrated 168bcede257SMatthew G. Knepley 169bcede257SMatthew G. Knepley Level: intermediate 170bcede257SMatthew G. Knepley 171db781477SPatrick Sanan .seealso: `PetscQuadratureGetOrder()`, `PetscQuadratureGetData()`, `PetscQuadratureSetData()` 172bcede257SMatthew G. Knepley @*/ 173*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscQuadratureSetOrder(PetscQuadrature q, PetscInt order) 174*d71ae5a4SJacob Faibussowitsch { 175bcede257SMatthew G. Knepley PetscFunctionBegin; 1762cd22861SMatthew G. Knepley PetscValidHeaderSpecific(q, PETSCQUADRATURE_CLASSID, 1); 177bcede257SMatthew G. Knepley q->order = order; 178bcede257SMatthew G. Knepley PetscFunctionReturn(0); 179bcede257SMatthew G. Knepley } 180bcede257SMatthew G. Knepley 181a6b92713SMatthew G. Knepley /*@ 182a6b92713SMatthew G. Knepley PetscQuadratureGetNumComponents - Return the number of components for functions to be integrated 183a6b92713SMatthew G. Knepley 184a6b92713SMatthew G. Knepley Not collective 185a6b92713SMatthew G. Knepley 186a6b92713SMatthew G. Knepley Input Parameter: 187a6b92713SMatthew G. Knepley . q - The PetscQuadrature object 188a6b92713SMatthew G. Knepley 189a6b92713SMatthew G. Knepley Output Parameter: 190a6b92713SMatthew G. Knepley . Nc - The number of components 191a6b92713SMatthew G. Knepley 192a6b92713SMatthew G. Knepley Note: We are performing an integral int f(x) . w(x) dx, where both f and w (the weight) have Nc components. 193a6b92713SMatthew G. Knepley 194a6b92713SMatthew G. Knepley Level: intermediate 195a6b92713SMatthew G. Knepley 196db781477SPatrick Sanan .seealso: `PetscQuadratureSetNumComponents()`, `PetscQuadratureGetData()`, `PetscQuadratureSetData()` 197a6b92713SMatthew G. Knepley @*/ 198*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscQuadratureGetNumComponents(PetscQuadrature q, PetscInt *Nc) 199*d71ae5a4SJacob Faibussowitsch { 200a6b92713SMatthew G. Knepley PetscFunctionBegin; 2012cd22861SMatthew G. Knepley PetscValidHeaderSpecific(q, PETSCQUADRATURE_CLASSID, 1); 202dadcf809SJacob Faibussowitsch PetscValidIntPointer(Nc, 2); 203a6b92713SMatthew G. Knepley *Nc = q->Nc; 204a6b92713SMatthew G. Knepley PetscFunctionReturn(0); 205a6b92713SMatthew G. Knepley } 206a6b92713SMatthew G. Knepley 207a6b92713SMatthew G. Knepley /*@ 208a6b92713SMatthew G. Knepley PetscQuadratureSetNumComponents - Return the number of components for functions to be integrated 209a6b92713SMatthew G. Knepley 210a6b92713SMatthew G. Knepley Not collective 211a6b92713SMatthew G. Knepley 212a6b92713SMatthew G. Knepley Input Parameters: 213a6b92713SMatthew G. Knepley + q - The PetscQuadrature object 214a6b92713SMatthew G. Knepley - Nc - The number of components 215a6b92713SMatthew G. Knepley 216a6b92713SMatthew G. Knepley Note: We are performing an integral int f(x) . w(x) dx, where both f and w (the weight) have Nc components. 217a6b92713SMatthew G. Knepley 218a6b92713SMatthew G. Knepley Level: intermediate 219a6b92713SMatthew G. Knepley 220db781477SPatrick Sanan .seealso: `PetscQuadratureGetNumComponents()`, `PetscQuadratureGetData()`, `PetscQuadratureSetData()` 221a6b92713SMatthew G. Knepley @*/ 222*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscQuadratureSetNumComponents(PetscQuadrature q, PetscInt Nc) 223*d71ae5a4SJacob Faibussowitsch { 224a6b92713SMatthew G. Knepley PetscFunctionBegin; 2252cd22861SMatthew G. Knepley PetscValidHeaderSpecific(q, PETSCQUADRATURE_CLASSID, 1); 226a6b92713SMatthew G. Knepley q->Nc = Nc; 227a6b92713SMatthew G. Knepley PetscFunctionReturn(0); 228a6b92713SMatthew G. Knepley } 229a6b92713SMatthew G. Knepley 23040d8ff71SMatthew G. Knepley /*@C 23140d8ff71SMatthew G. Knepley PetscQuadratureGetData - Returns the data defining the quadrature 23240d8ff71SMatthew G. Knepley 23340d8ff71SMatthew G. Knepley Not collective 23440d8ff71SMatthew G. Knepley 23540d8ff71SMatthew G. Knepley Input Parameter: 23640d8ff71SMatthew G. Knepley . q - The PetscQuadrature object 23740d8ff71SMatthew G. Knepley 23840d8ff71SMatthew G. Knepley Output Parameters: 23940d8ff71SMatthew G. Knepley + dim - The spatial dimension 240805e7170SToby Isaac . Nc - The number of components 24140d8ff71SMatthew G. Knepley . npoints - The number of quadrature points 24240d8ff71SMatthew G. Knepley . points - The coordinates of each quadrature point 24340d8ff71SMatthew G. Knepley - weights - The weight of each quadrature point 24440d8ff71SMatthew G. Knepley 24540d8ff71SMatthew G. Knepley Level: intermediate 24640d8ff71SMatthew G. Knepley 24795452b02SPatrick Sanan Fortran Notes: 24895452b02SPatrick Sanan From Fortran you must call PetscQuadratureRestoreData() when you are done with the data 2491fd49c25SBarry Smith 250db781477SPatrick Sanan .seealso: `PetscQuadratureCreate()`, `PetscQuadratureSetData()` 25140d8ff71SMatthew G. Knepley @*/ 252*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscQuadratureGetData(PetscQuadrature q, PetscInt *dim, PetscInt *Nc, PetscInt *npoints, const PetscReal *points[], const PetscReal *weights[]) 253*d71ae5a4SJacob Faibussowitsch { 25421454ff5SMatthew G. Knepley PetscFunctionBegin; 2552cd22861SMatthew G. Knepley PetscValidHeaderSpecific(q, PETSCQUADRATURE_CLASSID, 1); 25621454ff5SMatthew G. Knepley if (dim) { 257dadcf809SJacob Faibussowitsch PetscValidIntPointer(dim, 2); 25821454ff5SMatthew G. Knepley *dim = q->dim; 25921454ff5SMatthew G. Knepley } 260a6b92713SMatthew G. Knepley if (Nc) { 261dadcf809SJacob Faibussowitsch PetscValidIntPointer(Nc, 3); 262a6b92713SMatthew G. Knepley *Nc = q->Nc; 263a6b92713SMatthew G. Knepley } 26421454ff5SMatthew G. Knepley if (npoints) { 265dadcf809SJacob Faibussowitsch PetscValidIntPointer(npoints, 4); 26621454ff5SMatthew G. Knepley *npoints = q->numPoints; 26721454ff5SMatthew G. Knepley } 26821454ff5SMatthew G. Knepley if (points) { 269a6b92713SMatthew G. Knepley PetscValidPointer(points, 5); 27021454ff5SMatthew G. Knepley *points = q->points; 27121454ff5SMatthew G. Knepley } 27221454ff5SMatthew G. Knepley if (weights) { 273a6b92713SMatthew G. Knepley PetscValidPointer(weights, 6); 27421454ff5SMatthew G. Knepley *weights = q->weights; 27521454ff5SMatthew G. Knepley } 27621454ff5SMatthew G. Knepley PetscFunctionReturn(0); 27721454ff5SMatthew G. Knepley } 27821454ff5SMatthew G. Knepley 2794f9ab2b4SJed Brown /*@ 2804f9ab2b4SJed Brown PetscQuadratureEqual - determine whether two quadratures are equivalent 2814f9ab2b4SJed Brown 2824f9ab2b4SJed Brown Input Parameters: 2834f9ab2b4SJed Brown + A - A PetscQuadrature object 2844f9ab2b4SJed Brown - B - Another PetscQuadrature object 2854f9ab2b4SJed Brown 2864f9ab2b4SJed Brown Output Parameters: 2874f9ab2b4SJed Brown . equal - PETSC_TRUE if the quadratures are the same 2884f9ab2b4SJed Brown 2894f9ab2b4SJed Brown Level: intermediate 2904f9ab2b4SJed Brown 291db781477SPatrick Sanan .seealso: `PetscQuadratureCreate()` 2924f9ab2b4SJed Brown @*/ 293*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscQuadratureEqual(PetscQuadrature A, PetscQuadrature B, PetscBool *equal) 294*d71ae5a4SJacob Faibussowitsch { 2954f9ab2b4SJed Brown PetscFunctionBegin; 2964f9ab2b4SJed Brown PetscValidHeaderSpecific(A, PETSCQUADRATURE_CLASSID, 1); 2974f9ab2b4SJed Brown PetscValidHeaderSpecific(B, PETSCQUADRATURE_CLASSID, 2); 2984f9ab2b4SJed Brown PetscValidBoolPointer(equal, 3); 2994f9ab2b4SJed Brown *equal = PETSC_FALSE; 300ad540459SPierre Jolivet if (A->dim != B->dim || A->Nc != B->Nc || A->order != B->order || A->numPoints != B->numPoints) PetscFunctionReturn(0); 3014f9ab2b4SJed Brown for (PetscInt i = 0; i < A->numPoints * A->dim; i++) { 302ad540459SPierre Jolivet if (PetscAbsReal(A->points[i] - B->points[i]) > PETSC_SMALL) PetscFunctionReturn(0); 3034f9ab2b4SJed Brown } 3044f9ab2b4SJed Brown if (!A->weights && !B->weights) { 3054f9ab2b4SJed Brown *equal = PETSC_TRUE; 3064f9ab2b4SJed Brown PetscFunctionReturn(0); 3074f9ab2b4SJed Brown } 3084f9ab2b4SJed Brown if (A->weights && B->weights) { 3094f9ab2b4SJed Brown for (PetscInt i = 0; i < A->numPoints; i++) { 310ad540459SPierre Jolivet if (PetscAbsReal(A->weights[i] - B->weights[i]) > PETSC_SMALL) PetscFunctionReturn(0); 3114f9ab2b4SJed Brown } 3124f9ab2b4SJed Brown *equal = PETSC_TRUE; 3134f9ab2b4SJed Brown } 3144f9ab2b4SJed Brown PetscFunctionReturn(0); 3154f9ab2b4SJed Brown } 3164f9ab2b4SJed Brown 317*d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDTJacobianInverse_Internal(PetscInt m, PetscInt n, const PetscReal J[], PetscReal Jinv[]) 318*d71ae5a4SJacob Faibussowitsch { 319907761f8SToby Isaac PetscScalar *Js, *Jinvs; 320907761f8SToby Isaac PetscInt i, j, k; 321907761f8SToby Isaac PetscBLASInt bm, bn, info; 322907761f8SToby Isaac 323907761f8SToby Isaac PetscFunctionBegin; 324d4afb720SToby Isaac if (!m || !n) PetscFunctionReturn(0); 3259566063dSJacob Faibussowitsch PetscCall(PetscBLASIntCast(m, &bm)); 3269566063dSJacob Faibussowitsch PetscCall(PetscBLASIntCast(n, &bn)); 327907761f8SToby Isaac #if defined(PETSC_USE_COMPLEX) 3289566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(m * n, &Js, m * n, &Jinvs)); 32928222859SToby Isaac for (i = 0; i < m * n; i++) Js[i] = J[i]; 330907761f8SToby Isaac #else 331907761f8SToby Isaac Js = (PetscReal *)J; 332907761f8SToby Isaac Jinvs = Jinv; 333907761f8SToby Isaac #endif 334907761f8SToby Isaac if (m == n) { 335907761f8SToby Isaac PetscBLASInt *pivots; 336907761f8SToby Isaac PetscScalar *W; 337907761f8SToby Isaac 3389566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(m, &pivots, m, &W)); 339907761f8SToby Isaac 3409566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(Jinvs, Js, m * m)); 341792fecdfSBarry Smith PetscCallBLAS("LAPACKgetrf", LAPACKgetrf_(&bm, &bm, Jinvs, &bm, pivots, &info)); 34263a3b9bcSJacob Faibussowitsch PetscCheck(!info, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error returned from LAPACKgetrf %" PetscInt_FMT, (PetscInt)info); 343792fecdfSBarry Smith PetscCallBLAS("LAPACKgetri", LAPACKgetri_(&bm, Jinvs, &bm, pivots, W, &bm, &info)); 34463a3b9bcSJacob Faibussowitsch PetscCheck(!info, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error returned from LAPACKgetri %" PetscInt_FMT, (PetscInt)info); 3459566063dSJacob Faibussowitsch PetscCall(PetscFree2(pivots, W)); 346907761f8SToby Isaac } else if (m < n) { 347907761f8SToby Isaac PetscScalar *JJT; 348907761f8SToby Isaac PetscBLASInt *pivots; 349907761f8SToby Isaac PetscScalar *W; 350907761f8SToby Isaac 3519566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(m * m, &JJT)); 3529566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(m, &pivots, m, &W)); 353907761f8SToby Isaac for (i = 0; i < m; i++) { 354907761f8SToby Isaac for (j = 0; j < m; j++) { 355907761f8SToby Isaac PetscScalar val = 0.; 356907761f8SToby Isaac 357907761f8SToby Isaac for (k = 0; k < n; k++) val += Js[i * n + k] * Js[j * n + k]; 358907761f8SToby Isaac JJT[i * m + j] = val; 359907761f8SToby Isaac } 360907761f8SToby Isaac } 361907761f8SToby Isaac 362792fecdfSBarry Smith PetscCallBLAS("LAPACKgetrf", LAPACKgetrf_(&bm, &bm, JJT, &bm, pivots, &info)); 36363a3b9bcSJacob Faibussowitsch PetscCheck(!info, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error returned from LAPACKgetrf %" PetscInt_FMT, (PetscInt)info); 364792fecdfSBarry Smith PetscCallBLAS("LAPACKgetri", LAPACKgetri_(&bm, JJT, &bm, pivots, W, &bm, &info)); 36563a3b9bcSJacob Faibussowitsch PetscCheck(!info, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error returned from LAPACKgetri %" PetscInt_FMT, (PetscInt)info); 366907761f8SToby Isaac for (i = 0; i < n; i++) { 367907761f8SToby Isaac for (j = 0; j < m; j++) { 368907761f8SToby Isaac PetscScalar val = 0.; 369907761f8SToby Isaac 370907761f8SToby Isaac for (k = 0; k < m; k++) val += Js[k * n + i] * JJT[k * m + j]; 371907761f8SToby Isaac Jinvs[i * m + j] = val; 372907761f8SToby Isaac } 373907761f8SToby Isaac } 3749566063dSJacob Faibussowitsch PetscCall(PetscFree2(pivots, W)); 3759566063dSJacob Faibussowitsch PetscCall(PetscFree(JJT)); 376907761f8SToby Isaac } else { 377907761f8SToby Isaac PetscScalar *JTJ; 378907761f8SToby Isaac PetscBLASInt *pivots; 379907761f8SToby Isaac PetscScalar *W; 380907761f8SToby Isaac 3819566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(n * n, &JTJ)); 3829566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(n, &pivots, n, &W)); 383907761f8SToby Isaac for (i = 0; i < n; i++) { 384907761f8SToby Isaac for (j = 0; j < n; j++) { 385907761f8SToby Isaac PetscScalar val = 0.; 386907761f8SToby Isaac 387907761f8SToby Isaac for (k = 0; k < m; k++) val += Js[k * n + i] * Js[k * n + j]; 388907761f8SToby Isaac JTJ[i * n + j] = val; 389907761f8SToby Isaac } 390907761f8SToby Isaac } 391907761f8SToby Isaac 392792fecdfSBarry Smith PetscCallBLAS("LAPACKgetrf", LAPACKgetrf_(&bn, &bn, JTJ, &bn, pivots, &info)); 39363a3b9bcSJacob Faibussowitsch PetscCheck(!info, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error returned from LAPACKgetrf %" PetscInt_FMT, (PetscInt)info); 394792fecdfSBarry Smith PetscCallBLAS("LAPACKgetri", LAPACKgetri_(&bn, JTJ, &bn, pivots, W, &bn, &info)); 39563a3b9bcSJacob Faibussowitsch PetscCheck(!info, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error returned from LAPACKgetri %" PetscInt_FMT, (PetscInt)info); 396907761f8SToby Isaac for (i = 0; i < n; i++) { 397907761f8SToby Isaac for (j = 0; j < m; j++) { 398907761f8SToby Isaac PetscScalar val = 0.; 399907761f8SToby Isaac 400907761f8SToby Isaac for (k = 0; k < n; k++) val += JTJ[i * n + k] * Js[j * n + k]; 401907761f8SToby Isaac Jinvs[i * m + j] = val; 402907761f8SToby Isaac } 403907761f8SToby Isaac } 4049566063dSJacob Faibussowitsch PetscCall(PetscFree2(pivots, W)); 4059566063dSJacob Faibussowitsch PetscCall(PetscFree(JTJ)); 406907761f8SToby Isaac } 407907761f8SToby Isaac #if defined(PETSC_USE_COMPLEX) 40828222859SToby Isaac for (i = 0; i < m * n; i++) Jinv[i] = PetscRealPart(Jinvs[i]); 4099566063dSJacob Faibussowitsch PetscCall(PetscFree2(Js, Jinvs)); 410907761f8SToby Isaac #endif 411907761f8SToby Isaac PetscFunctionReturn(0); 412907761f8SToby Isaac } 413907761f8SToby Isaac 414907761f8SToby Isaac /*@ 415907761f8SToby Isaac PetscQuadraturePushForward - Push forward a quadrature functional under an affine transformation. 416907761f8SToby Isaac 417907761f8SToby Isaac Collecive on PetscQuadrature 418907761f8SToby Isaac 4194165533cSJose E. Roman Input Parameters: 420907761f8SToby Isaac + q - the quadrature functional 421907761f8SToby Isaac . imageDim - the dimension of the image of the transformation 422907761f8SToby Isaac . origin - a point in the original space 423907761f8SToby Isaac . originImage - the image of the origin under the transformation 424907761f8SToby Isaac . J - the Jacobian of the image: an [imageDim x dim] matrix in row major order 42528222859SToby 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] 426907761f8SToby Isaac 4274165533cSJose E. Roman Output Parameters: 428907761f8SToby 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. 429907761f8SToby Isaac 430907761f8SToby 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. 431907761f8SToby Isaac 4326c877ef6SSatish Balay Level: intermediate 4336c877ef6SSatish Balay 434db781477SPatrick Sanan .seealso: `PetscDTAltVPullback()`, `PetscDTAltVPullbackMatrix()` 435907761f8SToby Isaac @*/ 436*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscQuadraturePushForward(PetscQuadrature q, PetscInt imageDim, const PetscReal origin[], const PetscReal originImage[], const PetscReal J[], PetscInt formDegree, PetscQuadrature *Jinvstarq) 437*d71ae5a4SJacob Faibussowitsch { 438907761f8SToby Isaac PetscInt dim, Nc, imageNc, formSize, Ncopies, imageFormSize, Npoints, pt, i, j, c; 439907761f8SToby Isaac const PetscReal *points; 440907761f8SToby Isaac const PetscReal *weights; 441907761f8SToby Isaac PetscReal *imagePoints, *imageWeights; 442907761f8SToby Isaac PetscReal *Jinv; 443907761f8SToby Isaac PetscReal *Jinvstar; 444907761f8SToby Isaac 445907761f8SToby Isaac PetscFunctionBegin; 446d4afb720SToby Isaac PetscValidHeaderSpecific(q, PETSCQUADRATURE_CLASSID, 1); 44763a3b9bcSJacob 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); 4489566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(q, &dim, &Nc, &Npoints, &points, &weights)); 4499566063dSJacob Faibussowitsch PetscCall(PetscDTBinomialInt(dim, PetscAbsInt(formDegree), &formSize)); 45063a3b9bcSJacob 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); 451907761f8SToby Isaac Ncopies = Nc / formSize; 4529566063dSJacob Faibussowitsch PetscCall(PetscDTBinomialInt(imageDim, PetscAbsInt(formDegree), &imageFormSize)); 453907761f8SToby Isaac imageNc = Ncopies * imageFormSize; 4549566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(Npoints * imageDim, &imagePoints)); 4559566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(Npoints * imageNc, &imageWeights)); 4569566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(imageDim * dim, &Jinv, formSize * imageFormSize, &Jinvstar)); 4579566063dSJacob Faibussowitsch PetscCall(PetscDTJacobianInverse_Internal(imageDim, dim, J, Jinv)); 4589566063dSJacob Faibussowitsch PetscCall(PetscDTAltVPullbackMatrix(imageDim, dim, Jinv, formDegree, Jinvstar)); 459907761f8SToby Isaac for (pt = 0; pt < Npoints; pt++) { 460907761f8SToby Isaac const PetscReal *point = &points[pt * dim]; 461907761f8SToby Isaac PetscReal *imagePoint = &imagePoints[pt * imageDim]; 462907761f8SToby Isaac 463907761f8SToby Isaac for (i = 0; i < imageDim; i++) { 464907761f8SToby Isaac PetscReal val = originImage[i]; 465907761f8SToby Isaac 466907761f8SToby Isaac for (j = 0; j < dim; j++) val += J[i * dim + j] * (point[j] - origin[j]); 467907761f8SToby Isaac imagePoint[i] = val; 468907761f8SToby Isaac } 469907761f8SToby Isaac for (c = 0; c < Ncopies; c++) { 470907761f8SToby Isaac const PetscReal *form = &weights[pt * Nc + c * formSize]; 471907761f8SToby Isaac PetscReal *imageForm = &imageWeights[pt * imageNc + c * imageFormSize]; 472907761f8SToby Isaac 473907761f8SToby Isaac for (i = 0; i < imageFormSize; i++) { 474907761f8SToby Isaac PetscReal val = 0.; 475907761f8SToby Isaac 476907761f8SToby Isaac for (j = 0; j < formSize; j++) val += Jinvstar[i * formSize + j] * form[j]; 477907761f8SToby Isaac imageForm[i] = val; 478907761f8SToby Isaac } 479907761f8SToby Isaac } 480907761f8SToby Isaac } 4819566063dSJacob Faibussowitsch PetscCall(PetscQuadratureCreate(PetscObjectComm((PetscObject)q), Jinvstarq)); 4829566063dSJacob Faibussowitsch PetscCall(PetscQuadratureSetData(*Jinvstarq, imageDim, imageNc, Npoints, imagePoints, imageWeights)); 4839566063dSJacob Faibussowitsch PetscCall(PetscFree2(Jinv, Jinvstar)); 484907761f8SToby Isaac PetscFunctionReturn(0); 485907761f8SToby Isaac } 486907761f8SToby Isaac 48740d8ff71SMatthew G. Knepley /*@C 48840d8ff71SMatthew G. Knepley PetscQuadratureSetData - Sets the data defining the quadrature 48940d8ff71SMatthew G. Knepley 49040d8ff71SMatthew G. Knepley Not collective 49140d8ff71SMatthew G. Knepley 49240d8ff71SMatthew G. Knepley Input Parameters: 49340d8ff71SMatthew G. Knepley + q - The PetscQuadrature object 49440d8ff71SMatthew G. Knepley . dim - The spatial dimension 495e2b35d93SBarry Smith . Nc - The number of components 49640d8ff71SMatthew G. Knepley . npoints - The number of quadrature points 49740d8ff71SMatthew G. Knepley . points - The coordinates of each quadrature point 49840d8ff71SMatthew G. Knepley - weights - The weight of each quadrature point 49940d8ff71SMatthew G. Knepley 500c99e0549SMatthew 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. 501f2fd9e53SMatthew G. Knepley 50240d8ff71SMatthew G. Knepley Level: intermediate 50340d8ff71SMatthew G. Knepley 504db781477SPatrick Sanan .seealso: `PetscQuadratureCreate()`, `PetscQuadratureGetData()` 50540d8ff71SMatthew G. Knepley @*/ 506*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscQuadratureSetData(PetscQuadrature q, PetscInt dim, PetscInt Nc, PetscInt npoints, const PetscReal points[], const PetscReal weights[]) 507*d71ae5a4SJacob Faibussowitsch { 50821454ff5SMatthew G. Knepley PetscFunctionBegin; 5092cd22861SMatthew G. Knepley PetscValidHeaderSpecific(q, PETSCQUADRATURE_CLASSID, 1); 51021454ff5SMatthew G. Knepley if (dim >= 0) q->dim = dim; 511a6b92713SMatthew G. Knepley if (Nc >= 0) q->Nc = Nc; 51221454ff5SMatthew G. Knepley if (npoints >= 0) q->numPoints = npoints; 51321454ff5SMatthew G. Knepley if (points) { 514dadcf809SJacob Faibussowitsch PetscValidRealPointer(points, 5); 51521454ff5SMatthew G. Knepley q->points = points; 51621454ff5SMatthew G. Knepley } 51721454ff5SMatthew G. Knepley if (weights) { 518dadcf809SJacob Faibussowitsch PetscValidRealPointer(weights, 6); 51921454ff5SMatthew G. Knepley q->weights = weights; 52021454ff5SMatthew G. Knepley } 521f9fd7fdbSMatthew G. Knepley PetscFunctionReturn(0); 522f9fd7fdbSMatthew G. Knepley } 523f9fd7fdbSMatthew G. Knepley 524*d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscQuadratureView_Ascii(PetscQuadrature quad, PetscViewer v) 525*d71ae5a4SJacob Faibussowitsch { 526d9bac1caSLisandro Dalcin PetscInt q, d, c; 527d9bac1caSLisandro Dalcin PetscViewerFormat format; 528d9bac1caSLisandro Dalcin 529d9bac1caSLisandro Dalcin PetscFunctionBegin; 53063a3b9bcSJacob 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)); 53163a3b9bcSJacob Faibussowitsch else PetscCall(PetscViewerASCIIPrintf(v, "Quadrature of order %" PetscInt_FMT " on %" PetscInt_FMT " points (dim %" PetscInt_FMT ")\n", quad->order, quad->numPoints, quad->dim)); 5329566063dSJacob Faibussowitsch PetscCall(PetscViewerGetFormat(v, &format)); 533d9bac1caSLisandro Dalcin if (format != PETSC_VIEWER_ASCII_INFO_DETAIL) PetscFunctionReturn(0); 534d9bac1caSLisandro Dalcin for (q = 0; q < quad->numPoints; ++q) { 53563a3b9bcSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(v, "p%" PetscInt_FMT " (", q)); 5369566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIUseTabs(v, PETSC_FALSE)); 537d9bac1caSLisandro Dalcin for (d = 0; d < quad->dim; ++d) { 5389566063dSJacob Faibussowitsch if (d) PetscCall(PetscViewerASCIIPrintf(v, ", ")); 5399566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(v, "%+g", (double)quad->points[q * quad->dim + d])); 540d9bac1caSLisandro Dalcin } 5419566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(v, ") ")); 54263a3b9bcSJacob Faibussowitsch if (quad->Nc > 1) PetscCall(PetscViewerASCIIPrintf(v, "w%" PetscInt_FMT " (", q)); 543d9bac1caSLisandro Dalcin for (c = 0; c < quad->Nc; ++c) { 5449566063dSJacob Faibussowitsch if (c) PetscCall(PetscViewerASCIIPrintf(v, ", ")); 5459566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(v, "%+g", (double)quad->weights[q * quad->Nc + c])); 546d9bac1caSLisandro Dalcin } 5479566063dSJacob Faibussowitsch if (quad->Nc > 1) PetscCall(PetscViewerASCIIPrintf(v, ")")); 5489566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPrintf(v, "\n")); 5499566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIUseTabs(v, PETSC_TRUE)); 550d9bac1caSLisandro Dalcin } 551d9bac1caSLisandro Dalcin PetscFunctionReturn(0); 552d9bac1caSLisandro Dalcin } 553d9bac1caSLisandro Dalcin 55440d8ff71SMatthew G. Knepley /*@C 55540d8ff71SMatthew G. Knepley PetscQuadratureView - Views a PetscQuadrature object 55640d8ff71SMatthew G. Knepley 557d083f849SBarry Smith Collective on quad 55840d8ff71SMatthew G. Knepley 55940d8ff71SMatthew G. Knepley Input Parameters: 560d9bac1caSLisandro Dalcin + quad - The PetscQuadrature object 56140d8ff71SMatthew G. Knepley - viewer - The PetscViewer object 56240d8ff71SMatthew G. Knepley 56340d8ff71SMatthew G. Knepley Level: beginner 56440d8ff71SMatthew G. Knepley 565db781477SPatrick Sanan .seealso: `PetscQuadratureCreate()`, `PetscQuadratureGetData()` 56640d8ff71SMatthew G. Knepley @*/ 567*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscQuadratureView(PetscQuadrature quad, PetscViewer viewer) 568*d71ae5a4SJacob Faibussowitsch { 569d9bac1caSLisandro Dalcin PetscBool iascii; 570f9fd7fdbSMatthew G. Knepley 571f9fd7fdbSMatthew G. Knepley PetscFunctionBegin; 572d9bac1caSLisandro Dalcin PetscValidHeader(quad, 1); 573d9bac1caSLisandro Dalcin if (viewer) PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 5749566063dSJacob Faibussowitsch if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)quad), &viewer)); 5759566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 5769566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPushTab(viewer)); 5779566063dSJacob Faibussowitsch if (iascii) PetscCall(PetscQuadratureView_Ascii(quad, viewer)); 5789566063dSJacob Faibussowitsch PetscCall(PetscViewerASCIIPopTab(viewer)); 579bfa639d9SMatthew G. Knepley PetscFunctionReturn(0); 580bfa639d9SMatthew G. Knepley } 581bfa639d9SMatthew G. Knepley 58289710940SMatthew G. Knepley /*@C 58389710940SMatthew G. Knepley PetscQuadratureExpandComposite - Return a quadrature over the composite element, which has the original quadrature in each subelement 58489710940SMatthew G. Knepley 58589710940SMatthew G. Knepley Not collective 58689710940SMatthew G. Knepley 587d8d19677SJose E. Roman Input Parameters: 58889710940SMatthew G. Knepley + q - The original PetscQuadrature 58989710940SMatthew G. Knepley . numSubelements - The number of subelements the original element is divided into 59089710940SMatthew G. Knepley . v0 - An array of the initial points for each subelement 59189710940SMatthew G. Knepley - jac - An array of the Jacobian mappings from the reference to each subelement 59289710940SMatthew G. Knepley 59389710940SMatthew G. Knepley Output Parameters: 59489710940SMatthew G. Knepley . dim - The dimension 59589710940SMatthew G. Knepley 59689710940SMatthew G. Knepley Note: Together v0 and jac define an affine mapping from the original reference element to each subelement 59789710940SMatthew G. Knepley 598f5f57ec0SBarry Smith Not available from Fortran 599f5f57ec0SBarry Smith 60089710940SMatthew G. Knepley Level: intermediate 60189710940SMatthew G. Knepley 602db781477SPatrick Sanan .seealso: `PetscFECreate()`, `PetscSpaceGetDimension()`, `PetscDualSpaceGetDimension()` 60389710940SMatthew G. Knepley @*/ 604*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscQuadratureExpandComposite(PetscQuadrature q, PetscInt numSubelements, const PetscReal v0[], const PetscReal jac[], PetscQuadrature *qref) 605*d71ae5a4SJacob Faibussowitsch { 60689710940SMatthew G. Knepley const PetscReal *points, *weights; 60789710940SMatthew G. Knepley PetscReal *pointsRef, *weightsRef; 608a6b92713SMatthew G. Knepley PetscInt dim, Nc, order, npoints, npointsRef, c, p, cp, d, e; 60989710940SMatthew G. Knepley 61089710940SMatthew G. Knepley PetscFunctionBegin; 6112cd22861SMatthew G. Knepley PetscValidHeaderSpecific(q, PETSCQUADRATURE_CLASSID, 1); 612dadcf809SJacob Faibussowitsch PetscValidRealPointer(v0, 3); 613dadcf809SJacob Faibussowitsch PetscValidRealPointer(jac, 4); 61489710940SMatthew G. Knepley PetscValidPointer(qref, 5); 6159566063dSJacob Faibussowitsch PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, qref)); 6169566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetOrder(q, &order)); 6179566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(q, &dim, &Nc, &npoints, &points, &weights)); 61889710940SMatthew G. Knepley npointsRef = npoints * numSubelements; 6199566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(npointsRef * dim, &pointsRef)); 6209566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(npointsRef * Nc, &weightsRef)); 62189710940SMatthew G. Knepley for (c = 0; c < numSubelements; ++c) { 62289710940SMatthew G. Knepley for (p = 0; p < npoints; ++p) { 62389710940SMatthew G. Knepley for (d = 0; d < dim; ++d) { 62489710940SMatthew G. Knepley pointsRef[(c * npoints + p) * dim + d] = v0[c * dim + d]; 625ad540459SPierre Jolivet for (e = 0; e < dim; ++e) pointsRef[(c * npoints + p) * dim + d] += jac[(c * dim + d) * dim + e] * (points[p * dim + e] + 1.0); 62689710940SMatthew G. Knepley } 62789710940SMatthew G. Knepley /* Could also use detJ here */ 628a6b92713SMatthew G. Knepley for (cp = 0; cp < Nc; ++cp) weightsRef[(c * npoints + p) * Nc + cp] = weights[p * Nc + cp] / numSubelements; 62989710940SMatthew G. Knepley } 63089710940SMatthew G. Knepley } 6319566063dSJacob Faibussowitsch PetscCall(PetscQuadratureSetOrder(*qref, order)); 6329566063dSJacob Faibussowitsch PetscCall(PetscQuadratureSetData(*qref, dim, Nc, npointsRef, pointsRef, weightsRef)); 63389710940SMatthew G. Knepley PetscFunctionReturn(0); 63489710940SMatthew G. Knepley } 63589710940SMatthew G. Knepley 63694e21283SToby Isaac /* Compute the coefficients for the Jacobi polynomial recurrence, 63794e21283SToby Isaac * 63894e21283SToby Isaac * J^{a,b}_n(x) = (cnm1 + cnm1x * x) * J^{a,b}_{n-1}(x) - cnm2 * J^{a,b}_{n-2}(x). 63994e21283SToby Isaac */ 64094e21283SToby Isaac #define PetscDTJacobiRecurrence_Internal(n, a, b, cnm1, cnm1x, cnm2) \ 64194e21283SToby Isaac do { \ 64294e21283SToby Isaac PetscReal _a = (a); \ 64394e21283SToby Isaac PetscReal _b = (b); \ 64494e21283SToby Isaac PetscReal _n = (n); \ 64594e21283SToby Isaac if (n == 1) { \ 64694e21283SToby Isaac (cnm1) = (_a - _b) * 0.5; \ 64794e21283SToby Isaac (cnm1x) = (_a + _b + 2.) * 0.5; \ 64894e21283SToby Isaac (cnm2) = 0.; \ 64994e21283SToby Isaac } else { \ 65094e21283SToby Isaac PetscReal _2n = _n + _n; \ 65194e21283SToby Isaac PetscReal _d = (_2n * (_n + _a + _b) * (_2n + _a + _b - 2)); \ 65294e21283SToby Isaac PetscReal _n1 = (_2n + _a + _b - 1.) * (_a * _a - _b * _b); \ 65394e21283SToby Isaac PetscReal _n1x = (_2n + _a + _b - 1.) * (_2n + _a + _b) * (_2n + _a + _b - 2); \ 65494e21283SToby Isaac PetscReal _n2 = 2. * ((_n + _a - 1.) * (_n + _b - 1.) * (_2n + _a + _b)); \ 65594e21283SToby Isaac (cnm1) = _n1 / _d; \ 65694e21283SToby Isaac (cnm1x) = _n1x / _d; \ 65794e21283SToby Isaac (cnm2) = _n2 / _d; \ 65894e21283SToby Isaac } \ 65994e21283SToby Isaac } while (0) 66094e21283SToby Isaac 661fbdc3dfeSToby Isaac /*@ 662fbdc3dfeSToby Isaac PetscDTJacobiNorm - Compute the weighted L2 norm of a Jacobi polynomial. 663fbdc3dfeSToby Isaac 664fbdc3dfeSToby Isaac $\| P^{\alpha,\beta}_n \|_{\alpha,\beta}^2 = \int_{-1}^1 (1 + x)^{\alpha} (1 - x)^{\beta} P^{\alpha,\beta}_n (x)^2 dx.$ 665fbdc3dfeSToby Isaac 6664165533cSJose E. Roman Input Parameters: 667fbdc3dfeSToby Isaac - alpha - the left exponent > -1 668fbdc3dfeSToby Isaac . beta - the right exponent > -1 669fbdc3dfeSToby Isaac + n - the polynomial degree 670fbdc3dfeSToby Isaac 6714165533cSJose E. Roman Output Parameter: 672fbdc3dfeSToby Isaac . norm - the weighted L2 norm 673fbdc3dfeSToby Isaac 674fbdc3dfeSToby Isaac Level: beginner 675fbdc3dfeSToby Isaac 676db781477SPatrick Sanan .seealso: `PetscDTJacobiEval()` 677fbdc3dfeSToby Isaac @*/ 678*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDTJacobiNorm(PetscReal alpha, PetscReal beta, PetscInt n, PetscReal *norm) 679*d71ae5a4SJacob Faibussowitsch { 680fbdc3dfeSToby Isaac PetscReal twoab1; 681fbdc3dfeSToby Isaac PetscReal gr; 682fbdc3dfeSToby Isaac 683fbdc3dfeSToby Isaac PetscFunctionBegin; 68408401ef6SPierre Jolivet PetscCheck(alpha > -1., PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Exponent alpha %g <= -1. invalid", (double)alpha); 68508401ef6SPierre Jolivet PetscCheck(beta > -1., PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Exponent beta %g <= -1. invalid", (double)beta); 68663a3b9bcSJacob Faibussowitsch PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "n %" PetscInt_FMT " < 0 invalid", n); 687fbdc3dfeSToby Isaac twoab1 = PetscPowReal(2., alpha + beta + 1.); 688fbdc3dfeSToby Isaac #if defined(PETSC_HAVE_LGAMMA) 689fbdc3dfeSToby Isaac if (!n) { 690fbdc3dfeSToby Isaac gr = PetscExpReal(PetscLGamma(alpha + 1.) + PetscLGamma(beta + 1.) - PetscLGamma(alpha + beta + 2.)); 691fbdc3dfeSToby Isaac } else { 692fbdc3dfeSToby Isaac gr = PetscExpReal(PetscLGamma(n + alpha + 1.) + PetscLGamma(n + beta + 1.) - (PetscLGamma(n + 1.) + PetscLGamma(n + alpha + beta + 1.))) / (n + n + alpha + beta + 1.); 693fbdc3dfeSToby Isaac } 694fbdc3dfeSToby Isaac #else 695fbdc3dfeSToby Isaac { 696fbdc3dfeSToby Isaac PetscInt alphai = (PetscInt)alpha; 697fbdc3dfeSToby Isaac PetscInt betai = (PetscInt)beta; 698fbdc3dfeSToby Isaac PetscInt i; 699fbdc3dfeSToby Isaac 700fbdc3dfeSToby Isaac gr = n ? (1. / (n + n + alpha + beta + 1.)) : 1.; 701fbdc3dfeSToby Isaac if ((PetscReal)alphai == alpha) { 702fbdc3dfeSToby Isaac if (!n) { 703fbdc3dfeSToby Isaac for (i = 0; i < alphai; i++) gr *= (i + 1.) / (beta + i + 1.); 704fbdc3dfeSToby Isaac gr /= (alpha + beta + 1.); 705fbdc3dfeSToby Isaac } else { 706fbdc3dfeSToby Isaac for (i = 0; i < alphai; i++) gr *= (n + i + 1.) / (n + beta + i + 1.); 707fbdc3dfeSToby Isaac } 708fbdc3dfeSToby Isaac } else if ((PetscReal)betai == beta) { 709fbdc3dfeSToby Isaac if (!n) { 710fbdc3dfeSToby Isaac for (i = 0; i < betai; i++) gr *= (i + 1.) / (alpha + i + 2.); 711fbdc3dfeSToby Isaac gr /= (alpha + beta + 1.); 712fbdc3dfeSToby Isaac } else { 713fbdc3dfeSToby Isaac for (i = 0; i < betai; i++) gr *= (n + i + 1.) / (n + alpha + i + 1.); 714fbdc3dfeSToby Isaac } 715fbdc3dfeSToby Isaac } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "lgamma() - math routine is unavailable."); 716fbdc3dfeSToby Isaac } 717fbdc3dfeSToby Isaac #endif 718fbdc3dfeSToby Isaac *norm = PetscSqrtReal(twoab1 * gr); 719fbdc3dfeSToby Isaac PetscFunctionReturn(0); 720fbdc3dfeSToby Isaac } 721fbdc3dfeSToby Isaac 722*d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDTJacobiEval_Internal(PetscInt npoints, PetscReal a, PetscReal b, PetscInt k, const PetscReal *points, PetscInt ndegree, const PetscInt *degrees, PetscReal *p) 723*d71ae5a4SJacob Faibussowitsch { 72494e21283SToby Isaac PetscReal ak, bk; 72594e21283SToby Isaac PetscReal abk1; 72694e21283SToby Isaac PetscInt i, l, maxdegree; 72794e21283SToby Isaac 72894e21283SToby Isaac PetscFunctionBegin; 72994e21283SToby Isaac maxdegree = degrees[ndegree - 1] - k; 73094e21283SToby Isaac ak = a + k; 73194e21283SToby Isaac bk = b + k; 73294e21283SToby Isaac abk1 = a + b + k + 1.; 73394e21283SToby Isaac if (maxdegree < 0) { 7349371c9d4SSatish Balay for (i = 0; i < npoints; i++) 7359371c9d4SSatish Balay for (l = 0; l < ndegree; l++) p[i * ndegree + l] = 0.; 73694e21283SToby Isaac PetscFunctionReturn(0); 73794e21283SToby Isaac } 73894e21283SToby Isaac for (i = 0; i < npoints; i++) { 73994e21283SToby Isaac PetscReal pm1, pm2, x; 74094e21283SToby Isaac PetscReal cnm1, cnm1x, cnm2; 74194e21283SToby Isaac PetscInt j, m; 74294e21283SToby Isaac 74394e21283SToby Isaac x = points[i]; 74494e21283SToby Isaac pm2 = 1.; 74594e21283SToby Isaac PetscDTJacobiRecurrence_Internal(1, ak, bk, cnm1, cnm1x, cnm2); 74694e21283SToby Isaac pm1 = (cnm1 + cnm1x * x); 74794e21283SToby Isaac l = 0; 748ad540459SPierre Jolivet while (l < ndegree && degrees[l] - k < 0) p[l++] = 0.; 74994e21283SToby Isaac while (l < ndegree && degrees[l] - k == 0) { 75094e21283SToby Isaac p[l] = pm2; 75194e21283SToby Isaac for (m = 0; m < k; m++) p[l] *= (abk1 + m) * 0.5; 75294e21283SToby Isaac l++; 75394e21283SToby Isaac } 75494e21283SToby Isaac while (l < ndegree && degrees[l] - k == 1) { 75594e21283SToby Isaac p[l] = pm1; 75694e21283SToby Isaac for (m = 0; m < k; m++) p[l] *= (abk1 + 1 + m) * 0.5; 75794e21283SToby Isaac l++; 75894e21283SToby Isaac } 75994e21283SToby Isaac for (j = 2; j <= maxdegree; j++) { 76094e21283SToby Isaac PetscReal pp; 76194e21283SToby Isaac 76294e21283SToby Isaac PetscDTJacobiRecurrence_Internal(j, ak, bk, cnm1, cnm1x, cnm2); 76394e21283SToby Isaac pp = (cnm1 + cnm1x * x) * pm1 - cnm2 * pm2; 76494e21283SToby Isaac pm2 = pm1; 76594e21283SToby Isaac pm1 = pp; 76694e21283SToby Isaac while (l < ndegree && degrees[l] - k == j) { 76794e21283SToby Isaac p[l] = pp; 76894e21283SToby Isaac for (m = 0; m < k; m++) p[l] *= (abk1 + j + m) * 0.5; 76994e21283SToby Isaac l++; 77094e21283SToby Isaac } 77194e21283SToby Isaac } 77294e21283SToby Isaac p += ndegree; 77394e21283SToby Isaac } 77494e21283SToby Isaac PetscFunctionReturn(0); 77594e21283SToby Isaac } 77694e21283SToby Isaac 77737045ce4SJed Brown /*@ 778fbdc3dfeSToby 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$. 779fbdc3dfeSToby Isaac 7804165533cSJose E. Roman Input Parameters: 781fbdc3dfeSToby Isaac + alpha - the left exponent of the weight 782fbdc3dfeSToby Isaac . beta - the right exponetn of the weight 783fbdc3dfeSToby Isaac . npoints - the number of points to evaluate the polynomials at 784fbdc3dfeSToby Isaac . points - [npoints] array of point coordinates 785fbdc3dfeSToby Isaac . degree - the maximm degree polynomial space to evaluate, (degree + 1) will be evaluated total. 786fbdc3dfeSToby Isaac - k - the maximum derivative to evaluate in the jet, (k + 1) will be evaluated total. 787fbdc3dfeSToby Isaac 7886aad120cSJose E. Roman Output Parameters: 789fbdc3dfeSToby Isaac - p - an array containing the evaluations of the Jacobi polynomials's jets on the points. the size is (degree + 1) x 790fbdc3dfeSToby Isaac (k + 1) x npoints, which also describes the order of the dimensions of this three-dimensional array: the first 791fbdc3dfeSToby Isaac (slowest varying) dimension is polynomial degree; the second dimension is derivative order; the third (fastest 792fbdc3dfeSToby Isaac varying) dimension is the index of the evaluation point. 793fbdc3dfeSToby Isaac 794fbdc3dfeSToby Isaac Level: advanced 795fbdc3dfeSToby Isaac 796db781477SPatrick Sanan .seealso: `PetscDTJacobiEval()`, `PetscDTPKDEvalJet()` 797fbdc3dfeSToby Isaac @*/ 798*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDTJacobiEvalJet(PetscReal alpha, PetscReal beta, PetscInt npoints, const PetscReal points[], PetscInt degree, PetscInt k, PetscReal p[]) 799*d71ae5a4SJacob Faibussowitsch { 800fbdc3dfeSToby Isaac PetscInt i, j, l; 801fbdc3dfeSToby Isaac PetscInt *degrees; 802fbdc3dfeSToby Isaac PetscReal *psingle; 803fbdc3dfeSToby Isaac 804fbdc3dfeSToby Isaac PetscFunctionBegin; 805fbdc3dfeSToby Isaac if (degree == 0) { 806fbdc3dfeSToby Isaac PetscInt zero = 0; 807fbdc3dfeSToby Isaac 80848a46eb9SPierre Jolivet for (i = 0; i <= k; i++) PetscCall(PetscDTJacobiEval_Internal(npoints, alpha, beta, i, points, 1, &zero, &p[i * npoints])); 809fbdc3dfeSToby Isaac PetscFunctionReturn(0); 810fbdc3dfeSToby Isaac } 8119566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(degree + 1, °rees)); 8129566063dSJacob Faibussowitsch PetscCall(PetscMalloc1((degree + 1) * npoints, &psingle)); 813fbdc3dfeSToby Isaac for (i = 0; i <= degree; i++) degrees[i] = i; 814fbdc3dfeSToby Isaac for (i = 0; i <= k; i++) { 8159566063dSJacob Faibussowitsch PetscCall(PetscDTJacobiEval_Internal(npoints, alpha, beta, i, points, degree + 1, degrees, psingle)); 816fbdc3dfeSToby Isaac for (j = 0; j <= degree; j++) { 817ad540459SPierre Jolivet for (l = 0; l < npoints; l++) p[(j * (k + 1) + i) * npoints + l] = psingle[l * (degree + 1) + j]; 818fbdc3dfeSToby Isaac } 819fbdc3dfeSToby Isaac } 8209566063dSJacob Faibussowitsch PetscCall(PetscFree(psingle)); 8219566063dSJacob Faibussowitsch PetscCall(PetscFree(degrees)); 822fbdc3dfeSToby Isaac PetscFunctionReturn(0); 823fbdc3dfeSToby Isaac } 824fbdc3dfeSToby Isaac 825fbdc3dfeSToby Isaac /*@ 82694e21283SToby Isaac PetscDTJacobiEval - evaluate Jacobi polynomials for the weight function $(1.+x)^{\alpha} (1.-x)^{\beta}$ 82794e21283SToby Isaac at points 82894e21283SToby Isaac 82994e21283SToby Isaac Not Collective 83094e21283SToby Isaac 8314165533cSJose E. Roman Input Parameters: 83294e21283SToby Isaac + npoints - number of spatial points to evaluate at 83394e21283SToby Isaac . alpha - the left exponent > -1 83494e21283SToby Isaac . beta - the right exponent > -1 83594e21283SToby Isaac . points - array of locations to evaluate at 83694e21283SToby Isaac . ndegree - number of basis degrees to evaluate 83794e21283SToby Isaac - degrees - sorted array of degrees to evaluate 83894e21283SToby Isaac 8394165533cSJose E. Roman Output Parameters: 84094e21283SToby Isaac + B - row-oriented basis evaluation matrix B[point*ndegree + degree] (dimension npoints*ndegrees, allocated by caller) (or NULL) 84194e21283SToby Isaac . D - row-oriented derivative evaluation matrix (or NULL) 84294e21283SToby Isaac - D2 - row-oriented second derivative evaluation matrix (or NULL) 84394e21283SToby Isaac 84494e21283SToby Isaac Level: intermediate 84594e21283SToby Isaac 846db781477SPatrick Sanan .seealso: `PetscDTGaussQuadrature()` 84794e21283SToby Isaac @*/ 848*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDTJacobiEval(PetscInt npoints, PetscReal alpha, PetscReal beta, const PetscReal *points, PetscInt ndegree, const PetscInt *degrees, PetscReal *B, PetscReal *D, PetscReal *D2) 849*d71ae5a4SJacob Faibussowitsch { 85094e21283SToby Isaac PetscFunctionBegin; 85108401ef6SPierre Jolivet PetscCheck(alpha > -1., PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "alpha must be > -1."); 85208401ef6SPierre Jolivet PetscCheck(beta > -1., PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "beta must be > -1."); 85394e21283SToby Isaac if (!npoints || !ndegree) PetscFunctionReturn(0); 8549566063dSJacob Faibussowitsch if (B) PetscCall(PetscDTJacobiEval_Internal(npoints, alpha, beta, 0, points, ndegree, degrees, B)); 8559566063dSJacob Faibussowitsch if (D) PetscCall(PetscDTJacobiEval_Internal(npoints, alpha, beta, 1, points, ndegree, degrees, D)); 8569566063dSJacob Faibussowitsch if (D2) PetscCall(PetscDTJacobiEval_Internal(npoints, alpha, beta, 2, points, ndegree, degrees, D2)); 85794e21283SToby Isaac PetscFunctionReturn(0); 85894e21283SToby Isaac } 85994e21283SToby Isaac 86094e21283SToby Isaac /*@ 86194e21283SToby Isaac PetscDTLegendreEval - evaluate Legendre polynomials at points 86237045ce4SJed Brown 86337045ce4SJed Brown Not Collective 86437045ce4SJed Brown 8654165533cSJose E. Roman Input Parameters: 86637045ce4SJed Brown + npoints - number of spatial points to evaluate at 86737045ce4SJed Brown . points - array of locations to evaluate at 86837045ce4SJed Brown . ndegree - number of basis degrees to evaluate 86937045ce4SJed Brown - degrees - sorted array of degrees to evaluate 87037045ce4SJed Brown 8714165533cSJose E. Roman Output Parameters: 8720298fd71SBarry Smith + B - row-oriented basis evaluation matrix B[point*ndegree + degree] (dimension npoints*ndegrees, allocated by caller) (or NULL) 8730298fd71SBarry Smith . D - row-oriented derivative evaluation matrix (or NULL) 8740298fd71SBarry Smith - D2 - row-oriented second derivative evaluation matrix (or NULL) 87537045ce4SJed Brown 87637045ce4SJed Brown Level: intermediate 87737045ce4SJed Brown 878db781477SPatrick Sanan .seealso: `PetscDTGaussQuadrature()` 87937045ce4SJed Brown @*/ 880*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDTLegendreEval(PetscInt npoints, const PetscReal *points, PetscInt ndegree, const PetscInt *degrees, PetscReal *B, PetscReal *D, PetscReal *D2) 881*d71ae5a4SJacob Faibussowitsch { 88237045ce4SJed Brown PetscFunctionBegin; 8839566063dSJacob Faibussowitsch PetscCall(PetscDTJacobiEval(npoints, 0., 0., points, ndegree, degrees, B, D, D2)); 88437045ce4SJed Brown PetscFunctionReturn(0); 88537045ce4SJed Brown } 88637045ce4SJed Brown 887fbdc3dfeSToby Isaac /*@ 888fbdc3dfeSToby 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) 889fbdc3dfeSToby Isaac 890fbdc3dfeSToby Isaac Input Parameters: 891fbdc3dfeSToby Isaac + len - the desired length of the degree tuple 892fbdc3dfeSToby Isaac - index - the index to convert: should be >= 0 893fbdc3dfeSToby Isaac 894fbdc3dfeSToby Isaac Output Parameter: 895fbdc3dfeSToby Isaac . degtup - will be filled with a tuple of degrees 896fbdc3dfeSToby Isaac 897fbdc3dfeSToby Isaac Level: beginner 898fbdc3dfeSToby Isaac 899fbdc3dfeSToby Isaac Note: for two tuples x and y with the same degree sum, partial degree sums over the final elements of the tuples 900fbdc3dfeSToby 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 901fbdc3dfeSToby Isaac last two elements is smaller for the former, so (2, 1, 1) < (1, 2, 1). 902fbdc3dfeSToby Isaac 903db781477SPatrick Sanan .seealso: `PetscDTGradedOrderToIndex()` 904fbdc3dfeSToby Isaac @*/ 905*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDTIndexToGradedOrder(PetscInt len, PetscInt index, PetscInt degtup[]) 906*d71ae5a4SJacob Faibussowitsch { 907fbdc3dfeSToby Isaac PetscInt i, total; 908fbdc3dfeSToby Isaac PetscInt sum; 909fbdc3dfeSToby Isaac 910fbdc3dfeSToby Isaac PetscFunctionBeginHot; 91108401ef6SPierre Jolivet PetscCheck(len >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "length must be non-negative"); 91208401ef6SPierre Jolivet PetscCheck(index >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "index must be non-negative"); 913fbdc3dfeSToby Isaac total = 1; 914fbdc3dfeSToby Isaac sum = 0; 915fbdc3dfeSToby Isaac while (index >= total) { 916fbdc3dfeSToby Isaac index -= total; 917fbdc3dfeSToby Isaac total = (total * (len + sum)) / (sum + 1); 918fbdc3dfeSToby Isaac sum++; 919fbdc3dfeSToby Isaac } 920fbdc3dfeSToby Isaac for (i = 0; i < len; i++) { 921fbdc3dfeSToby Isaac PetscInt c; 922fbdc3dfeSToby Isaac 923fbdc3dfeSToby Isaac degtup[i] = sum; 924fbdc3dfeSToby Isaac for (c = 0, total = 1; c < sum; c++) { 925fbdc3dfeSToby Isaac /* going into the loop, total is the number of way to have a tuple of sum exactly c with length len - 1 - i */ 926fbdc3dfeSToby Isaac if (index < total) break; 927fbdc3dfeSToby Isaac index -= total; 928fbdc3dfeSToby Isaac total = (total * (len - 1 - i + c)) / (c + 1); 929fbdc3dfeSToby Isaac degtup[i]--; 930fbdc3dfeSToby Isaac } 931fbdc3dfeSToby Isaac sum -= degtup[i]; 932fbdc3dfeSToby Isaac } 933fbdc3dfeSToby Isaac PetscFunctionReturn(0); 934fbdc3dfeSToby Isaac } 935fbdc3dfeSToby Isaac 936fbdc3dfeSToby Isaac /*@ 937fbdc3dfeSToby Isaac PetscDTGradedOrderToIndex - convert a tuple into an index in a graded order, the inverse of PetscDTIndexToGradedOrder(). 938fbdc3dfeSToby Isaac 939fbdc3dfeSToby Isaac Input Parameters: 940fbdc3dfeSToby Isaac + len - the length of the degree tuple 941fbdc3dfeSToby Isaac - degtup - tuple with this length 942fbdc3dfeSToby Isaac 943fbdc3dfeSToby Isaac Output Parameter: 944fbdc3dfeSToby Isaac . index - index in graded order: >= 0 945fbdc3dfeSToby Isaac 946fbdc3dfeSToby Isaac Level: Beginner 947fbdc3dfeSToby Isaac 948fbdc3dfeSToby Isaac Note: for two tuples x and y with the same degree sum, partial degree sums over the final elements of the tuples 949fbdc3dfeSToby 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 950fbdc3dfeSToby Isaac last two elements is smaller for the former, so (2, 1, 1) < (1, 2, 1). 951fbdc3dfeSToby Isaac 952db781477SPatrick Sanan .seealso: `PetscDTIndexToGradedOrder()` 953fbdc3dfeSToby Isaac @*/ 954*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDTGradedOrderToIndex(PetscInt len, const PetscInt degtup[], PetscInt *index) 955*d71ae5a4SJacob Faibussowitsch { 956fbdc3dfeSToby Isaac PetscInt i, idx, sum, total; 957fbdc3dfeSToby Isaac 958fbdc3dfeSToby Isaac PetscFunctionBeginHot; 95908401ef6SPierre Jolivet PetscCheck(len >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "length must be non-negative"); 960fbdc3dfeSToby Isaac for (i = 0, sum = 0; i < len; i++) sum += degtup[i]; 961fbdc3dfeSToby Isaac idx = 0; 962fbdc3dfeSToby Isaac total = 1; 963fbdc3dfeSToby Isaac for (i = 0; i < sum; i++) { 964fbdc3dfeSToby Isaac idx += total; 965fbdc3dfeSToby Isaac total = (total * (len + i)) / (i + 1); 966fbdc3dfeSToby Isaac } 967fbdc3dfeSToby Isaac for (i = 0; i < len - 1; i++) { 968fbdc3dfeSToby Isaac PetscInt c; 969fbdc3dfeSToby Isaac 970fbdc3dfeSToby Isaac total = 1; 971fbdc3dfeSToby Isaac sum -= degtup[i]; 972fbdc3dfeSToby Isaac for (c = 0; c < sum; c++) { 973fbdc3dfeSToby Isaac idx += total; 974fbdc3dfeSToby Isaac total = (total * (len - 1 - i + c)) / (c + 1); 975fbdc3dfeSToby Isaac } 976fbdc3dfeSToby Isaac } 977fbdc3dfeSToby Isaac *index = idx; 978fbdc3dfeSToby Isaac PetscFunctionReturn(0); 979fbdc3dfeSToby Isaac } 980fbdc3dfeSToby Isaac 981e3aa2e09SToby Isaac static PetscBool PKDCite = PETSC_FALSE; 982e3aa2e09SToby Isaac const char PKDCitation[] = "@article{Kirby2010,\n" 983e3aa2e09SToby Isaac " title={Singularity-free evaluation of collapsed-coordinate orthogonal polynomials},\n" 984e3aa2e09SToby Isaac " author={Kirby, Robert C},\n" 985e3aa2e09SToby Isaac " journal={ACM Transactions on Mathematical Software (TOMS)},\n" 986e3aa2e09SToby Isaac " volume={37},\n" 987e3aa2e09SToby Isaac " number={1},\n" 988e3aa2e09SToby Isaac " pages={1--16},\n" 989e3aa2e09SToby Isaac " year={2010},\n" 990e3aa2e09SToby Isaac " publisher={ACM New York, NY, USA}\n}\n"; 991e3aa2e09SToby Isaac 992fbdc3dfeSToby Isaac /*@ 993d8f25ad8SToby Isaac PetscDTPKDEvalJet - Evaluate the jet (function and derivatives) of the Proriol-Koornwinder-Dubiner (PKD) basis for 994fbdc3dfeSToby Isaac the space of polynomials up to a given degree. The PKD basis is L2-orthonormal on the biunit simplex (which is used 995fbdc3dfeSToby Isaac as the reference element for finite elements in PETSc), which makes it a stable basis to use for evaluating 996fbdc3dfeSToby Isaac polynomials in that domain. 997fbdc3dfeSToby Isaac 9984165533cSJose E. Roman Input Parameters: 999fbdc3dfeSToby Isaac + dim - the number of variables in the multivariate polynomials 1000fbdc3dfeSToby Isaac . npoints - the number of points to evaluate the polynomials at 1001fbdc3dfeSToby Isaac . points - [npoints x dim] array of point coordinates 1002fbdc3dfeSToby 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. 1003fbdc3dfeSToby Isaac - k - the maximum order partial derivative to evaluate in the jet. There are (dim + k choose dim) partial derivatives 1004fbdc3dfeSToby Isaac in the jet. Choosing k = 0 means to evaluate just the function and no derivatives 1005fbdc3dfeSToby Isaac 10066aad120cSJose E. Roman Output Parameters: 1007fbdc3dfeSToby Isaac - p - an array containing the evaluations of the PKD polynomials' jets on the points. The size is ((dim + degree) 1008fbdc3dfeSToby Isaac choose dim) x ((dim + k) choose dim) x npoints, which also describes the order of the dimensions of this 1009fbdc3dfeSToby Isaac three-dimensional array: the first (slowest varying) dimension is basis function index; the second dimension is jet 1010fbdc3dfeSToby Isaac index; the third (fastest varying) dimension is the index of the evaluation point. 1011fbdc3dfeSToby Isaac 1012fbdc3dfeSToby Isaac Level: advanced 1013fbdc3dfeSToby Isaac 1014fbdc3dfeSToby Isaac Note: The ordering of the basis functions, and the ordering of the derivatives in the jet, both follow the graded 1015fbdc3dfeSToby Isaac ordering of PetscDTIndexToGradedOrder() and PetscDTGradedOrderToIndex(). For example, in 3D, the polynomial with 1016d8f25ad8SToby 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); 1017fbdc3dfeSToby 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). 1018fbdc3dfeSToby Isaac 1019e3aa2e09SToby Isaac The implementation uses Kirby's singularity-free evaluation algorithm, https://doi.org/10.1145/1644001.1644006. 1020e3aa2e09SToby Isaac 1021db781477SPatrick Sanan .seealso: `PetscDTGradedOrderToIndex()`, `PetscDTIndexToGradedOrder()`, `PetscDTJacobiEvalJet()` 1022fbdc3dfeSToby Isaac @*/ 1023*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDTPKDEvalJet(PetscInt dim, PetscInt npoints, const PetscReal points[], PetscInt degree, PetscInt k, PetscReal p[]) 1024*d71ae5a4SJacob Faibussowitsch { 1025fbdc3dfeSToby Isaac PetscInt degidx, kidx, d, pt; 1026fbdc3dfeSToby Isaac PetscInt Nk, Ndeg; 1027fbdc3dfeSToby Isaac PetscInt *ktup, *degtup; 1028fbdc3dfeSToby Isaac PetscReal *scales, initscale, scaleexp; 1029fbdc3dfeSToby Isaac 1030fbdc3dfeSToby Isaac PetscFunctionBegin; 10319566063dSJacob Faibussowitsch PetscCall(PetscCitationsRegister(PKDCitation, &PKDCite)); 10329566063dSJacob Faibussowitsch PetscCall(PetscDTBinomialInt(dim + k, k, &Nk)); 10339566063dSJacob Faibussowitsch PetscCall(PetscDTBinomialInt(degree + dim, degree, &Ndeg)); 10349566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(dim, °tup, dim, &ktup)); 10359566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(Ndeg, &scales)); 1036fbdc3dfeSToby Isaac initscale = 1.; 1037fbdc3dfeSToby Isaac if (dim > 1) { 10389566063dSJacob Faibussowitsch PetscCall(PetscDTBinomial(dim, 2, &scaleexp)); 10392f613bf5SBarry Smith initscale = PetscPowReal(2., scaleexp * 0.5); 1040fbdc3dfeSToby Isaac } 1041fbdc3dfeSToby Isaac for (degidx = 0; degidx < Ndeg; degidx++) { 1042fbdc3dfeSToby Isaac PetscInt e, i; 1043fbdc3dfeSToby Isaac PetscInt m1idx = -1, m2idx = -1; 1044fbdc3dfeSToby Isaac PetscInt n; 1045fbdc3dfeSToby Isaac PetscInt degsum; 1046fbdc3dfeSToby Isaac PetscReal alpha; 1047fbdc3dfeSToby Isaac PetscReal cnm1, cnm1x, cnm2; 1048fbdc3dfeSToby Isaac PetscReal norm; 1049fbdc3dfeSToby Isaac 10509566063dSJacob Faibussowitsch PetscCall(PetscDTIndexToGradedOrder(dim, degidx, degtup)); 10519371c9d4SSatish Balay for (d = dim - 1; d >= 0; d--) 10529371c9d4SSatish Balay if (degtup[d]) break; 1053fbdc3dfeSToby Isaac if (d < 0) { /* constant is 1 everywhere, all derivatives are zero */ 1054fbdc3dfeSToby Isaac scales[degidx] = initscale; 1055fbdc3dfeSToby Isaac for (e = 0; e < dim; e++) { 10569566063dSJacob Faibussowitsch PetscCall(PetscDTJacobiNorm(e, 0., 0, &norm)); 1057fbdc3dfeSToby Isaac scales[degidx] /= norm; 1058fbdc3dfeSToby Isaac } 1059fbdc3dfeSToby Isaac for (i = 0; i < npoints; i++) p[degidx * Nk * npoints + i] = 1.; 1060fbdc3dfeSToby Isaac for (i = 0; i < (Nk - 1) * npoints; i++) p[(degidx * Nk + 1) * npoints + i] = 0.; 1061fbdc3dfeSToby Isaac continue; 1062fbdc3dfeSToby Isaac } 1063fbdc3dfeSToby Isaac n = degtup[d]; 1064fbdc3dfeSToby Isaac degtup[d]--; 10659566063dSJacob Faibussowitsch PetscCall(PetscDTGradedOrderToIndex(dim, degtup, &m1idx)); 1066fbdc3dfeSToby Isaac if (degtup[d] > 0) { 1067fbdc3dfeSToby Isaac degtup[d]--; 10689566063dSJacob Faibussowitsch PetscCall(PetscDTGradedOrderToIndex(dim, degtup, &m2idx)); 1069fbdc3dfeSToby Isaac degtup[d]++; 1070fbdc3dfeSToby Isaac } 1071fbdc3dfeSToby Isaac degtup[d]++; 1072fbdc3dfeSToby Isaac for (e = 0, degsum = 0; e < d; e++) degsum += degtup[e]; 1073fbdc3dfeSToby Isaac alpha = 2 * degsum + d; 1074fbdc3dfeSToby Isaac PetscDTJacobiRecurrence_Internal(n, alpha, 0., cnm1, cnm1x, cnm2); 1075fbdc3dfeSToby Isaac 1076fbdc3dfeSToby Isaac scales[degidx] = initscale; 1077fbdc3dfeSToby Isaac for (e = 0, degsum = 0; e < dim; e++) { 1078fbdc3dfeSToby Isaac PetscInt f; 1079fbdc3dfeSToby Isaac PetscReal ealpha; 1080fbdc3dfeSToby Isaac PetscReal enorm; 1081fbdc3dfeSToby Isaac 1082fbdc3dfeSToby Isaac ealpha = 2 * degsum + e; 1083fbdc3dfeSToby Isaac for (f = 0; f < degsum; f++) scales[degidx] *= 2.; 10849566063dSJacob Faibussowitsch PetscCall(PetscDTJacobiNorm(ealpha, 0., degtup[e], &enorm)); 1085fbdc3dfeSToby Isaac scales[degidx] /= enorm; 1086fbdc3dfeSToby Isaac degsum += degtup[e]; 1087fbdc3dfeSToby Isaac } 1088fbdc3dfeSToby Isaac 1089fbdc3dfeSToby Isaac for (pt = 0; pt < npoints; pt++) { 1090fbdc3dfeSToby Isaac /* compute the multipliers */ 1091fbdc3dfeSToby Isaac PetscReal thetanm1, thetanm1x, thetanm2; 1092fbdc3dfeSToby Isaac 1093fbdc3dfeSToby Isaac thetanm1x = dim - (d + 1) + 2. * points[pt * dim + d]; 1094fbdc3dfeSToby Isaac for (e = d + 1; e < dim; e++) thetanm1x += points[pt * dim + e]; 1095fbdc3dfeSToby Isaac thetanm1x *= 0.5; 1096fbdc3dfeSToby Isaac thetanm1 = (2. - (dim - (d + 1))); 1097fbdc3dfeSToby Isaac for (e = d + 1; e < dim; e++) thetanm1 -= points[pt * dim + e]; 1098fbdc3dfeSToby Isaac thetanm1 *= 0.5; 1099fbdc3dfeSToby Isaac thetanm2 = thetanm1 * thetanm1; 1100fbdc3dfeSToby Isaac 1101fbdc3dfeSToby Isaac for (kidx = 0; kidx < Nk; kidx++) { 1102fbdc3dfeSToby Isaac PetscInt f; 1103fbdc3dfeSToby Isaac 11049566063dSJacob Faibussowitsch PetscCall(PetscDTIndexToGradedOrder(dim, kidx, ktup)); 1105fbdc3dfeSToby Isaac /* first sum in the same derivative terms */ 1106fbdc3dfeSToby Isaac p[(degidx * Nk + kidx) * npoints + pt] = (cnm1 * thetanm1 + cnm1x * thetanm1x) * p[(m1idx * Nk + kidx) * npoints + pt]; 1107ad540459SPierre Jolivet if (m2idx >= 0) p[(degidx * Nk + kidx) * npoints + pt] -= cnm2 * thetanm2 * p[(m2idx * Nk + kidx) * npoints + pt]; 1108fbdc3dfeSToby Isaac 1109fbdc3dfeSToby Isaac for (f = d; f < dim; f++) { 1110fbdc3dfeSToby Isaac PetscInt km1idx, mplty = ktup[f]; 1111fbdc3dfeSToby Isaac 1112fbdc3dfeSToby Isaac if (!mplty) continue; 1113fbdc3dfeSToby Isaac ktup[f]--; 11149566063dSJacob Faibussowitsch PetscCall(PetscDTGradedOrderToIndex(dim, ktup, &km1idx)); 1115fbdc3dfeSToby Isaac 1116fbdc3dfeSToby Isaac /* the derivative of cnm1x * thetanm1x wrt x variable f is 0.5 * cnm1x if f > d otherwise it is cnm1x */ 1117fbdc3dfeSToby Isaac /* the derivative of cnm1 * thetanm1 wrt x variable f is 0 if f == d, otherwise it is -0.5 * cnm1 */ 1118fbdc3dfeSToby Isaac /* the derivative of -cnm2 * thetanm2 wrt x variable f is 0 if f == d, otherwise it is cnm2 * thetanm1 */ 1119fbdc3dfeSToby Isaac if (f > d) { 1120fbdc3dfeSToby Isaac PetscInt f2; 1121fbdc3dfeSToby Isaac 1122fbdc3dfeSToby Isaac p[(degidx * Nk + kidx) * npoints + pt] += mplty * 0.5 * (cnm1x - cnm1) * p[(m1idx * Nk + km1idx) * npoints + pt]; 1123fbdc3dfeSToby Isaac if (m2idx >= 0) { 1124fbdc3dfeSToby Isaac p[(degidx * Nk + kidx) * npoints + pt] += mplty * cnm2 * thetanm1 * p[(m2idx * Nk + km1idx) * npoints + pt]; 1125fbdc3dfeSToby Isaac /* second derivatives of -cnm2 * thetanm2 wrt x variable f,f2 is like - 0.5 * cnm2 */ 1126fbdc3dfeSToby Isaac for (f2 = f; f2 < dim; f2++) { 1127fbdc3dfeSToby Isaac PetscInt km2idx, mplty2 = ktup[f2]; 1128fbdc3dfeSToby Isaac PetscInt factor; 1129fbdc3dfeSToby Isaac 1130fbdc3dfeSToby Isaac if (!mplty2) continue; 1131fbdc3dfeSToby Isaac ktup[f2]--; 11329566063dSJacob Faibussowitsch PetscCall(PetscDTGradedOrderToIndex(dim, ktup, &km2idx)); 1133fbdc3dfeSToby Isaac 1134fbdc3dfeSToby Isaac factor = mplty * mplty2; 1135fbdc3dfeSToby Isaac if (f == f2) factor /= 2; 1136fbdc3dfeSToby Isaac p[(degidx * Nk + kidx) * npoints + pt] -= 0.5 * factor * cnm2 * p[(m2idx * Nk + km2idx) * npoints + pt]; 1137fbdc3dfeSToby Isaac ktup[f2]++; 1138fbdc3dfeSToby Isaac } 11393034baaeSToby Isaac } 1140fbdc3dfeSToby Isaac } else { 1141fbdc3dfeSToby Isaac p[(degidx * Nk + kidx) * npoints + pt] += mplty * cnm1x * p[(m1idx * Nk + km1idx) * npoints + pt]; 1142fbdc3dfeSToby Isaac } 1143fbdc3dfeSToby Isaac ktup[f]++; 1144fbdc3dfeSToby Isaac } 1145fbdc3dfeSToby Isaac } 1146fbdc3dfeSToby Isaac } 1147fbdc3dfeSToby Isaac } 1148fbdc3dfeSToby Isaac for (degidx = 0; degidx < Ndeg; degidx++) { 1149fbdc3dfeSToby Isaac PetscReal scale = scales[degidx]; 1150fbdc3dfeSToby Isaac PetscInt i; 1151fbdc3dfeSToby Isaac 1152fbdc3dfeSToby Isaac for (i = 0; i < Nk * npoints; i++) p[degidx * Nk * npoints + i] *= scale; 1153fbdc3dfeSToby Isaac } 11549566063dSJacob Faibussowitsch PetscCall(PetscFree(scales)); 11559566063dSJacob Faibussowitsch PetscCall(PetscFree2(degtup, ktup)); 1156fbdc3dfeSToby Isaac PetscFunctionReturn(0); 1157fbdc3dfeSToby Isaac } 1158fbdc3dfeSToby Isaac 1159d8f25ad8SToby Isaac /*@ 1160d8f25ad8SToby Isaac PetscDTPTrimmedSize - The size of the trimmed polynomial space of k-forms with a given degree and form degree, 1161d8f25ad8SToby Isaac which can be evaluated in PetscDTPTrimmedEvalJet(). 1162d8f25ad8SToby Isaac 1163d8f25ad8SToby Isaac Input Parameters: 1164d8f25ad8SToby Isaac + dim - the number of variables in the multivariate polynomials 1165d8f25ad8SToby Isaac . degree - the degree (sum of degrees on the variables in a monomial) of the trimmed polynomial space. 1166d8f25ad8SToby Isaac - formDegree - the degree of the form 1167d8f25ad8SToby Isaac 11686aad120cSJose E. Roman Output Parameters: 1169d8f25ad8SToby Isaac - size - The number ((dim + degree) choose (dim + formDegree)) x ((degree + formDegree - 1) choose (formDegree)) 1170d8f25ad8SToby Isaac 1171d8f25ad8SToby Isaac Level: advanced 1172d8f25ad8SToby Isaac 1173db781477SPatrick Sanan .seealso: `PetscDTPTrimmedEvalJet()` 1174d8f25ad8SToby Isaac @*/ 1175*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDTPTrimmedSize(PetscInt dim, PetscInt degree, PetscInt formDegree, PetscInt *size) 1176*d71ae5a4SJacob Faibussowitsch { 1177d8f25ad8SToby Isaac PetscInt Nrk, Nbpt; // number of trimmed polynomials 1178d8f25ad8SToby Isaac 1179d8f25ad8SToby Isaac PetscFunctionBegin; 1180d8f25ad8SToby Isaac formDegree = PetscAbsInt(formDegree); 11819566063dSJacob Faibussowitsch PetscCall(PetscDTBinomialInt(degree + dim, degree + formDegree, &Nbpt)); 11829566063dSJacob Faibussowitsch PetscCall(PetscDTBinomialInt(degree + formDegree - 1, formDegree, &Nrk)); 1183d8f25ad8SToby Isaac Nbpt *= Nrk; 1184d8f25ad8SToby Isaac *size = Nbpt; 1185d8f25ad8SToby Isaac PetscFunctionReturn(0); 1186d8f25ad8SToby Isaac } 1187d8f25ad8SToby Isaac 1188d8f25ad8SToby Isaac /* there was a reference implementation based on section 4.4 of Arnold, Falk & Winther (acta numerica, 2006), but it 1189d8f25ad8SToby Isaac * was inferior to this implementation */ 1190*d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDTPTrimmedEvalJet_Internal(PetscInt dim, PetscInt npoints, const PetscReal points[], PetscInt degree, PetscInt formDegree, PetscInt jetDegree, PetscReal p[]) 1191*d71ae5a4SJacob Faibussowitsch { 1192d8f25ad8SToby Isaac PetscInt formDegreeOrig = formDegree; 1193d8f25ad8SToby Isaac PetscBool formNegative = (formDegreeOrig < 0) ? PETSC_TRUE : PETSC_FALSE; 1194d8f25ad8SToby Isaac 1195d8f25ad8SToby Isaac PetscFunctionBegin; 1196d8f25ad8SToby Isaac formDegree = PetscAbsInt(formDegreeOrig); 1197d8f25ad8SToby Isaac if (formDegree == 0) { 11989566063dSJacob Faibussowitsch PetscCall(PetscDTPKDEvalJet(dim, npoints, points, degree, jetDegree, p)); 1199d8f25ad8SToby Isaac PetscFunctionReturn(0); 1200d8f25ad8SToby Isaac } 1201d8f25ad8SToby Isaac if (formDegree == dim) { 12029566063dSJacob Faibussowitsch PetscCall(PetscDTPKDEvalJet(dim, npoints, points, degree - 1, jetDegree, p)); 1203d8f25ad8SToby Isaac PetscFunctionReturn(0); 1204d8f25ad8SToby Isaac } 1205d8f25ad8SToby Isaac PetscInt Nbpt; 12069566063dSJacob Faibussowitsch PetscCall(PetscDTPTrimmedSize(dim, degree, formDegree, &Nbpt)); 1207d8f25ad8SToby Isaac PetscInt Nf; 12089566063dSJacob Faibussowitsch PetscCall(PetscDTBinomialInt(dim, formDegree, &Nf)); 1209d8f25ad8SToby Isaac PetscInt Nk; 12109566063dSJacob Faibussowitsch PetscCall(PetscDTBinomialInt(dim + jetDegree, dim, &Nk)); 12119566063dSJacob Faibussowitsch PetscCall(PetscArrayzero(p, Nbpt * Nf * Nk * npoints)); 1212d8f25ad8SToby Isaac 1213d8f25ad8SToby Isaac PetscInt Nbpm1; // number of scalar polynomials up to degree - 1; 12149566063dSJacob Faibussowitsch PetscCall(PetscDTBinomialInt(dim + degree - 1, dim, &Nbpm1)); 1215d8f25ad8SToby Isaac PetscReal *p_scalar; 12169566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(Nbpm1 * Nk * npoints, &p_scalar)); 12179566063dSJacob Faibussowitsch PetscCall(PetscDTPKDEvalJet(dim, npoints, points, degree - 1, jetDegree, p_scalar)); 1218d8f25ad8SToby Isaac PetscInt total = 0; 1219d8f25ad8SToby Isaac // First add the full polynomials up to degree - 1 into the basis: take the scalar 1220d8f25ad8SToby Isaac // and copy one for each form component 1221d8f25ad8SToby Isaac for (PetscInt i = 0; i < Nbpm1; i++) { 1222d8f25ad8SToby Isaac const PetscReal *src = &p_scalar[i * Nk * npoints]; 1223d8f25ad8SToby Isaac for (PetscInt f = 0; f < Nf; f++) { 1224d8f25ad8SToby Isaac PetscReal *dest = &p[(total++ * Nf + f) * Nk * npoints]; 12259566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(dest, src, Nk * npoints)); 1226d8f25ad8SToby Isaac } 1227d8f25ad8SToby Isaac } 1228d8f25ad8SToby Isaac PetscInt *form_atoms; 12299566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(formDegree + 1, &form_atoms)); 1230d8f25ad8SToby Isaac // construct the interior product pattern 1231d8f25ad8SToby Isaac PetscInt(*pattern)[3]; 1232d8f25ad8SToby Isaac PetscInt Nf1; // number of formDegree + 1 forms 12339566063dSJacob Faibussowitsch PetscCall(PetscDTBinomialInt(dim, formDegree + 1, &Nf1)); 1234d8f25ad8SToby Isaac PetscInt nnz = Nf1 * (formDegree + 1); 12359566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(Nf1 * (formDegree + 1), &pattern)); 12369566063dSJacob Faibussowitsch PetscCall(PetscDTAltVInteriorPattern(dim, formDegree + 1, pattern)); 1237d8f25ad8SToby Isaac PetscReal centroid = (1. - dim) / (dim + 1.); 1238d8f25ad8SToby Isaac PetscInt *deriv; 12399566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(dim, &deriv)); 1240d8f25ad8SToby Isaac for (PetscInt d = dim; d >= formDegree + 1; d--) { 1241d8f25ad8SToby Isaac PetscInt Nfd1; // number of formDegree + 1 forms in dimension d that include dx_0 1242d8f25ad8SToby Isaac // (equal to the number of formDegree forms in dimension d-1) 12439566063dSJacob Faibussowitsch PetscCall(PetscDTBinomialInt(d - 1, formDegree, &Nfd1)); 1244d8f25ad8SToby Isaac // The number of homogeneous (degree-1) scalar polynomials in d variables 1245d8f25ad8SToby Isaac PetscInt Nh; 12469566063dSJacob Faibussowitsch PetscCall(PetscDTBinomialInt(d - 1 + degree - 1, d - 1, &Nh)); 1247d8f25ad8SToby Isaac const PetscReal *h_scalar = &p_scalar[(Nbpm1 - Nh) * Nk * npoints]; 1248d8f25ad8SToby Isaac for (PetscInt b = 0; b < Nh; b++) { 1249d8f25ad8SToby Isaac const PetscReal *h_s = &h_scalar[b * Nk * npoints]; 1250d8f25ad8SToby Isaac for (PetscInt f = 0; f < Nfd1; f++) { 1251d8f25ad8SToby Isaac // construct all formDegree+1 forms that start with dx_(dim - d) /\ ... 1252d8f25ad8SToby Isaac form_atoms[0] = dim - d; 12539566063dSJacob Faibussowitsch PetscCall(PetscDTEnumSubset(d - 1, formDegree, f, &form_atoms[1])); 1254ad540459SPierre Jolivet for (PetscInt i = 0; i < formDegree; i++) form_atoms[1 + i] += form_atoms[0] + 1; 1255d8f25ad8SToby Isaac PetscInt f_ind; // index of the resulting form 12569566063dSJacob Faibussowitsch PetscCall(PetscDTSubsetIndex(dim, formDegree + 1, form_atoms, &f_ind)); 1257d8f25ad8SToby Isaac PetscReal *p_f = &p[total++ * Nf * Nk * npoints]; 1258d8f25ad8SToby Isaac for (PetscInt nz = 0; nz < nnz; nz++) { 1259d8f25ad8SToby Isaac PetscInt i = pattern[nz][0]; // formDegree component 1260d8f25ad8SToby Isaac PetscInt j = pattern[nz][1]; // (formDegree + 1) component 1261d8f25ad8SToby Isaac PetscInt v = pattern[nz][2]; // coordinate component 1262d8f25ad8SToby Isaac PetscReal scale = v < 0 ? -1. : 1.; 1263d8f25ad8SToby Isaac 1264d8f25ad8SToby Isaac i = formNegative ? (Nf - 1 - i) : i; 1265d8f25ad8SToby Isaac scale = (formNegative && (i & 1)) ? -scale : scale; 1266d8f25ad8SToby Isaac v = v < 0 ? -(v + 1) : v; 1267ad540459SPierre Jolivet if (j != f_ind) continue; 1268d8f25ad8SToby Isaac PetscReal *p_i = &p_f[i * Nk * npoints]; 1269d8f25ad8SToby Isaac for (PetscInt jet = 0; jet < Nk; jet++) { 1270d8f25ad8SToby Isaac const PetscReal *h_jet = &h_s[jet * npoints]; 1271d8f25ad8SToby Isaac PetscReal *p_jet = &p_i[jet * npoints]; 1272d8f25ad8SToby Isaac 1273ad540459SPierre Jolivet for (PetscInt pt = 0; pt < npoints; pt++) p_jet[pt] += scale * h_jet[pt] * (points[pt * dim + v] - centroid); 12749566063dSJacob Faibussowitsch PetscCall(PetscDTIndexToGradedOrder(dim, jet, deriv)); 1275d8f25ad8SToby Isaac deriv[v]++; 1276d8f25ad8SToby Isaac PetscReal mult = deriv[v]; 1277d8f25ad8SToby Isaac PetscInt l; 12789566063dSJacob Faibussowitsch PetscCall(PetscDTGradedOrderToIndex(dim, deriv, &l)); 1279ad540459SPierre Jolivet if (l >= Nk) continue; 1280d8f25ad8SToby Isaac p_jet = &p_i[l * npoints]; 1281ad540459SPierre Jolivet for (PetscInt pt = 0; pt < npoints; pt++) p_jet[pt] += scale * mult * h_jet[pt]; 1282d8f25ad8SToby Isaac deriv[v]--; 1283d8f25ad8SToby Isaac } 1284d8f25ad8SToby Isaac } 1285d8f25ad8SToby Isaac } 1286d8f25ad8SToby Isaac } 1287d8f25ad8SToby Isaac } 128808401ef6SPierre Jolivet PetscCheck(total == Nbpt, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Incorrectly counted P trimmed polynomials"); 12899566063dSJacob Faibussowitsch PetscCall(PetscFree(deriv)); 12909566063dSJacob Faibussowitsch PetscCall(PetscFree(pattern)); 12919566063dSJacob Faibussowitsch PetscCall(PetscFree(form_atoms)); 12929566063dSJacob Faibussowitsch PetscCall(PetscFree(p_scalar)); 1293d8f25ad8SToby Isaac PetscFunctionReturn(0); 1294d8f25ad8SToby Isaac } 1295d8f25ad8SToby Isaac 1296d8f25ad8SToby Isaac /*@ 1297d8f25ad8SToby Isaac PetscDTPTrimmedEvalJet - Evaluate the jet (function and derivatives) of a basis of the trimmed polynomial k-forms up to 1298d8f25ad8SToby Isaac a given degree. 1299d8f25ad8SToby Isaac 1300d8f25ad8SToby Isaac Input Parameters: 1301d8f25ad8SToby Isaac + dim - the number of variables in the multivariate polynomials 1302d8f25ad8SToby Isaac . npoints - the number of points to evaluate the polynomials at 1303d8f25ad8SToby Isaac . points - [npoints x dim] array of point coordinates 1304d8f25ad8SToby Isaac . degree - the degree (sum of degrees on the variables in a monomial) of the trimmed polynomial space to evaluate. 1305d8f25ad8SToby Isaac There are ((dim + degree) choose (dim + formDegree)) x ((degree + formDegree - 1) choose (formDegree)) polynomials in this space. 1306d8f25ad8SToby Isaac (You can use PetscDTPTrimmedSize() to compute this size.) 1307d8f25ad8SToby Isaac . formDegree - the degree of the form 1308d8f25ad8SToby Isaac - jetDegree - the maximum order partial derivative to evaluate in the jet. There are ((dim + jetDegree) choose dim) partial derivatives 1309d8f25ad8SToby Isaac in the jet. Choosing jetDegree = 0 means to evaluate just the function and no derivatives 1310d8f25ad8SToby Isaac 13116aad120cSJose E. Roman Output Parameters: 1312d8f25ad8SToby Isaac - p - an array containing the evaluations of the PKD polynomials' jets on the points. The size is 1313d8f25ad8SToby Isaac PetscDTPTrimmedSize() x ((dim + formDegree) choose dim) x ((dim + k) choose dim) x npoints, 1314d8f25ad8SToby Isaac which also describes the order of the dimensions of this 1315d8f25ad8SToby Isaac four-dimensional array: 1316d8f25ad8SToby Isaac the first (slowest varying) dimension is basis function index; 1317d8f25ad8SToby Isaac the second dimension is component of the form; 1318d8f25ad8SToby Isaac the third dimension is jet index; 1319d8f25ad8SToby Isaac the fourth (fastest varying) dimension is the index of the evaluation point. 1320d8f25ad8SToby Isaac 1321d8f25ad8SToby Isaac Level: advanced 1322d8f25ad8SToby Isaac 1323d8f25ad8SToby Isaac Note: The ordering of the basis functions is not graded, so the basis functions are not nested by degree like PetscDTPKDEvalJet(). 1324d8f25ad8SToby Isaac The basis functions are not an L2-orthonormal basis on any particular domain. 1325d8f25ad8SToby Isaac 1326d8f25ad8SToby Isaac The implementation is based on the description of the trimmed polynomials up to degree r as 1327d8f25ad8SToby Isaac the direct sum of polynomials up to degree (r-1) and the Koszul differential applied to 1328d8f25ad8SToby Isaac homogeneous polynomials of degree (r-1). 1329d8f25ad8SToby Isaac 1330db781477SPatrick Sanan .seealso: `PetscDTPKDEvalJet()`, `PetscDTPTrimmedSize()` 1331d8f25ad8SToby Isaac @*/ 1332*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDTPTrimmedEvalJet(PetscInt dim, PetscInt npoints, const PetscReal points[], PetscInt degree, PetscInt formDegree, PetscInt jetDegree, PetscReal p[]) 1333*d71ae5a4SJacob Faibussowitsch { 1334d8f25ad8SToby Isaac PetscFunctionBegin; 13359566063dSJacob Faibussowitsch PetscCall(PetscDTPTrimmedEvalJet_Internal(dim, npoints, points, degree, formDegree, jetDegree, p)); 1336d8f25ad8SToby Isaac PetscFunctionReturn(0); 1337d8f25ad8SToby Isaac } 1338d8f25ad8SToby Isaac 1339e6a796c3SToby Isaac /* solve the symmetric tridiagonal eigenvalue system, writing the eigenvalues into eigs and the eigenvectors into V 1340e6a796c3SToby Isaac * with lds n; diag and subdiag are overwritten */ 1341*d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDTSymmetricTridiagonalEigensolve(PetscInt n, PetscReal diag[], PetscReal subdiag[], PetscReal eigs[], PetscScalar V[]) 1342*d71ae5a4SJacob Faibussowitsch { 1343e6a796c3SToby Isaac char jobz = 'V'; /* eigenvalues and eigenvectors */ 1344e6a796c3SToby Isaac char range = 'A'; /* all eigenvalues will be found */ 1345e6a796c3SToby Isaac PetscReal VL = 0.; /* ignored because range is 'A' */ 1346e6a796c3SToby Isaac PetscReal VU = 0.; /* ignored because range is 'A' */ 1347e6a796c3SToby Isaac PetscBLASInt IL = 0; /* ignored because range is 'A' */ 1348e6a796c3SToby Isaac PetscBLASInt IU = 0; /* ignored because range is 'A' */ 1349e6a796c3SToby Isaac PetscReal abstol = 0.; /* unused */ 1350e6a796c3SToby Isaac PetscBLASInt bn, bm, ldz; /* bm will equal bn on exit */ 1351e6a796c3SToby Isaac PetscBLASInt *isuppz; 1352e6a796c3SToby Isaac PetscBLASInt lwork, liwork; 1353e6a796c3SToby Isaac PetscReal workquery; 1354e6a796c3SToby Isaac PetscBLASInt iworkquery; 1355e6a796c3SToby Isaac PetscBLASInt *iwork; 1356e6a796c3SToby Isaac PetscBLASInt info; 1357e6a796c3SToby Isaac PetscReal *work = NULL; 1358e6a796c3SToby Isaac 1359e6a796c3SToby Isaac PetscFunctionBegin; 1360e6a796c3SToby Isaac #if !defined(PETSCDTGAUSSIANQUADRATURE_EIG) 1361e6a796c3SToby Isaac SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "A LAPACK symmetric tridiagonal eigensolver could not be found"); 1362e6a796c3SToby Isaac #endif 13639566063dSJacob Faibussowitsch PetscCall(PetscBLASIntCast(n, &bn)); 13649566063dSJacob Faibussowitsch PetscCall(PetscBLASIntCast(n, &ldz)); 1365e6a796c3SToby Isaac #if !defined(PETSC_MISSING_LAPACK_STEGR) 13669566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(2 * n, &isuppz)); 1367e6a796c3SToby Isaac lwork = -1; 1368e6a796c3SToby Isaac liwork = -1; 1369792fecdfSBarry Smith PetscCallBLAS("LAPACKstegr", LAPACKstegr_(&jobz, &range, &bn, diag, subdiag, &VL, &VU, &IL, &IU, &abstol, &bm, eigs, V, &ldz, isuppz, &workquery, &lwork, &iworkquery, &liwork, &info)); 137028b400f6SJacob Faibussowitsch PetscCheck(!info, PETSC_COMM_SELF, PETSC_ERR_PLIB, "xSTEGR error"); 1371e6a796c3SToby Isaac lwork = (PetscBLASInt)workquery; 1372e6a796c3SToby Isaac liwork = (PetscBLASInt)iworkquery; 13739566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(lwork, &work, liwork, &iwork)); 13749566063dSJacob Faibussowitsch PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF)); 1375792fecdfSBarry Smith PetscCallBLAS("LAPACKstegr", LAPACKstegr_(&jobz, &range, &bn, diag, subdiag, &VL, &VU, &IL, &IU, &abstol, &bm, eigs, V, &ldz, isuppz, work, &lwork, iwork, &liwork, &info)); 13769566063dSJacob Faibussowitsch PetscCall(PetscFPTrapPop()); 137728b400f6SJacob Faibussowitsch PetscCheck(!info, PETSC_COMM_SELF, PETSC_ERR_PLIB, "xSTEGR error"); 13789566063dSJacob Faibussowitsch PetscCall(PetscFree2(work, iwork)); 13799566063dSJacob Faibussowitsch PetscCall(PetscFree(isuppz)); 1380e6a796c3SToby Isaac #elif !defined(PETSC_MISSING_LAPACK_STEQR) 1381e6a796c3SToby Isaac jobz = 'I'; /* Compute eigenvalues and eigenvectors of the 1382e6a796c3SToby Isaac tridiagonal matrix. Z is initialized to the identity 1383e6a796c3SToby Isaac matrix. */ 13849566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(PetscMax(1, 2 * n - 2), &work)); 1385792fecdfSBarry Smith PetscCallBLAS("LAPACKsteqr", LAPACKsteqr_("I", &bn, diag, subdiag, V, &ldz, work, &info)); 13869566063dSJacob Faibussowitsch PetscCall(PetscFPTrapPop()); 138728b400f6SJacob Faibussowitsch PetscCheck(!info, PETSC_COMM_SELF, PETSC_ERR_PLIB, "xSTEQR error"); 13889566063dSJacob Faibussowitsch PetscCall(PetscFree(work)); 13899566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(eigs, diag, n)); 1390e6a796c3SToby Isaac #endif 1391e6a796c3SToby Isaac PetscFunctionReturn(0); 1392e6a796c3SToby Isaac } 1393e6a796c3SToby Isaac 1394e6a796c3SToby Isaac /* Formula for the weights at the endpoints (-1 and 1) of Gauss-Lobatto-Jacobi 1395e6a796c3SToby Isaac * quadrature rules on the interval [-1, 1] */ 1396*d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDTGaussLobattoJacobiEndweights_Internal(PetscInt n, PetscReal alpha, PetscReal beta, PetscReal *leftw, PetscReal *rightw) 1397*d71ae5a4SJacob Faibussowitsch { 1398e6a796c3SToby Isaac PetscReal twoab1; 1399e6a796c3SToby Isaac PetscInt m = n - 2; 1400e6a796c3SToby Isaac PetscReal a = alpha + 1.; 1401e6a796c3SToby Isaac PetscReal b = beta + 1.; 1402e6a796c3SToby Isaac PetscReal gra, grb; 1403e6a796c3SToby Isaac 1404e6a796c3SToby Isaac PetscFunctionBegin; 1405e6a796c3SToby Isaac twoab1 = PetscPowReal(2., a + b - 1.); 1406e6a796c3SToby Isaac #if defined(PETSC_HAVE_LGAMMA) 14079371c9d4SSatish Balay grb = PetscExpReal(2. * PetscLGamma(b + 1.) + PetscLGamma(m + 1.) + PetscLGamma(m + a + 1.) - (PetscLGamma(m + b + 1) + PetscLGamma(m + a + b + 1.))); 14089371c9d4SSatish Balay gra = PetscExpReal(2. * PetscLGamma(a + 1.) + PetscLGamma(m + 1.) + PetscLGamma(m + b + 1.) - (PetscLGamma(m + a + 1) + PetscLGamma(m + a + b + 1.))); 1409e6a796c3SToby Isaac #else 1410e6a796c3SToby Isaac { 1411e6a796c3SToby Isaac PetscInt alphai = (PetscInt)alpha; 1412e6a796c3SToby Isaac PetscInt betai = (PetscInt)beta; 1413e6a796c3SToby Isaac 1414e6a796c3SToby Isaac if ((PetscReal)alphai == alpha && (PetscReal)betai == beta) { 1415e6a796c3SToby Isaac PetscReal binom1, binom2; 1416e6a796c3SToby Isaac 14179566063dSJacob Faibussowitsch PetscCall(PetscDTBinomial(m + b, b, &binom1)); 14189566063dSJacob Faibussowitsch PetscCall(PetscDTBinomial(m + a + b, b, &binom2)); 1419e6a796c3SToby Isaac grb = 1. / (binom1 * binom2); 14209566063dSJacob Faibussowitsch PetscCall(PetscDTBinomial(m + a, a, &binom1)); 14219566063dSJacob Faibussowitsch PetscCall(PetscDTBinomial(m + a + b, a, &binom2)); 1422e6a796c3SToby Isaac gra = 1. / (binom1 * binom2); 1423e6a796c3SToby Isaac } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "lgamma() - math routine is unavailable."); 1424e6a796c3SToby Isaac } 1425e6a796c3SToby Isaac #endif 1426e6a796c3SToby Isaac *leftw = twoab1 * grb / b; 1427e6a796c3SToby Isaac *rightw = twoab1 * gra / a; 1428e6a796c3SToby Isaac PetscFunctionReturn(0); 1429e6a796c3SToby Isaac } 1430e6a796c3SToby Isaac 1431e6a796c3SToby Isaac /* Evaluates the nth jacobi polynomial with weight parameters a,b at a point x. 1432e6a796c3SToby Isaac Recurrence relations implemented from the pseudocode given in Karniadakis and Sherwin, Appendix B */ 1433*d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode PetscDTComputeJacobi(PetscReal a, PetscReal b, PetscInt n, PetscReal x, PetscReal *P) 1434*d71ae5a4SJacob Faibussowitsch { 143594e21283SToby Isaac PetscReal pn1, pn2; 143694e21283SToby Isaac PetscReal cnm1, cnm1x, cnm2; 1437e6a796c3SToby Isaac PetscInt k; 1438e6a796c3SToby Isaac 1439e6a796c3SToby Isaac PetscFunctionBegin; 14409371c9d4SSatish Balay if (!n) { 14419371c9d4SSatish Balay *P = 1.0; 14429371c9d4SSatish Balay PetscFunctionReturn(0); 14439371c9d4SSatish Balay } 144494e21283SToby Isaac PetscDTJacobiRecurrence_Internal(1, a, b, cnm1, cnm1x, cnm2); 144594e21283SToby Isaac pn2 = 1.; 144694e21283SToby Isaac pn1 = cnm1 + cnm1x * x; 14479371c9d4SSatish Balay if (n == 1) { 14489371c9d4SSatish Balay *P = pn1; 14499371c9d4SSatish Balay PetscFunctionReturn(0); 14509371c9d4SSatish Balay } 1451e6a796c3SToby Isaac *P = 0.0; 1452e6a796c3SToby Isaac for (k = 2; k < n + 1; ++k) { 145394e21283SToby Isaac PetscDTJacobiRecurrence_Internal(k, a, b, cnm1, cnm1x, cnm2); 1454e6a796c3SToby Isaac 145594e21283SToby Isaac *P = (cnm1 + cnm1x * x) * pn1 - cnm2 * pn2; 1456e6a796c3SToby Isaac pn2 = pn1; 1457e6a796c3SToby Isaac pn1 = *P; 1458e6a796c3SToby Isaac } 1459e6a796c3SToby Isaac PetscFunctionReturn(0); 1460e6a796c3SToby Isaac } 1461e6a796c3SToby Isaac 1462e6a796c3SToby Isaac /* Evaluates the first derivative of P_{n}^{a,b} at a point x. */ 1463*d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode PetscDTComputeJacobiDerivative(PetscReal a, PetscReal b, PetscInt n, PetscReal x, PetscInt k, PetscReal *P) 1464*d71ae5a4SJacob Faibussowitsch { 1465e6a796c3SToby Isaac PetscReal nP; 1466e6a796c3SToby Isaac PetscInt i; 1467e6a796c3SToby Isaac 1468e6a796c3SToby Isaac PetscFunctionBegin; 146917a42bb7SSatish Balay *P = 0.0; 147017a42bb7SSatish Balay if (k > n) PetscFunctionReturn(0); 14719566063dSJacob Faibussowitsch PetscCall(PetscDTComputeJacobi(a + k, b + k, n - k, x, &nP)); 1472e6a796c3SToby Isaac for (i = 0; i < k; i++) nP *= (a + b + n + 1. + i) * 0.5; 1473e6a796c3SToby Isaac *P = nP; 1474e6a796c3SToby Isaac PetscFunctionReturn(0); 1475e6a796c3SToby Isaac } 1476e6a796c3SToby Isaac 1477*d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDTGaussJacobiQuadrature_Newton_Internal(PetscInt npoints, PetscReal a, PetscReal b, PetscReal x[], PetscReal w[]) 1478*d71ae5a4SJacob Faibussowitsch { 1479e6a796c3SToby Isaac PetscInt maxIter = 100; 148094e21283SToby Isaac PetscReal eps = PetscExpReal(0.75 * PetscLogReal(PETSC_MACHINE_EPSILON)); 1481200b5abcSJed Brown PetscReal a1, a6, gf; 1482e6a796c3SToby Isaac PetscInt k; 1483e6a796c3SToby Isaac 1484e6a796c3SToby Isaac PetscFunctionBegin; 1485e6a796c3SToby Isaac 1486e6a796c3SToby Isaac a1 = PetscPowReal(2.0, a + b + 1); 148794e21283SToby Isaac #if defined(PETSC_HAVE_LGAMMA) 1488200b5abcSJed Brown { 1489200b5abcSJed Brown PetscReal a2, a3, a4, a5; 149094e21283SToby Isaac a2 = PetscLGamma(a + npoints + 1); 149194e21283SToby Isaac a3 = PetscLGamma(b + npoints + 1); 149294e21283SToby Isaac a4 = PetscLGamma(a + b + npoints + 1); 149394e21283SToby Isaac a5 = PetscLGamma(npoints + 1); 149494e21283SToby Isaac gf = PetscExpReal(a2 + a3 - (a4 + a5)); 1495200b5abcSJed Brown } 1496e6a796c3SToby Isaac #else 1497e6a796c3SToby Isaac { 1498e6a796c3SToby Isaac PetscInt ia, ib; 1499e6a796c3SToby Isaac 1500e6a796c3SToby Isaac ia = (PetscInt)a; 1501e6a796c3SToby Isaac ib = (PetscInt)b; 150294e21283SToby Isaac gf = 1.; 150394e21283SToby Isaac if (ia == a && ia >= 0) { /* compute ratio of rising factorals wrt a */ 150494e21283SToby Isaac for (k = 0; k < ia; k++) gf *= (npoints + 1. + k) / (npoints + b + 1. + k); 150594e21283SToby Isaac } else if (b == b && ib >= 0) { /* compute ratio of rising factorials wrt b */ 150694e21283SToby Isaac for (k = 0; k < ib; k++) gf *= (npoints + 1. + k) / (npoints + a + 1. + k); 150794e21283SToby Isaac } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "lgamma() - math routine is unavailable."); 1508e6a796c3SToby Isaac } 1509e6a796c3SToby Isaac #endif 1510e6a796c3SToby Isaac 151194e21283SToby Isaac a6 = a1 * gf; 1512e6a796c3SToby Isaac /* Computes the m roots of P_{m}^{a,b} on [-1,1] by Newton's method with Chebyshev points as initial guesses. 1513e6a796c3SToby Isaac Algorithm implemented from the pseudocode given by Karniadakis and Sherwin and Python in FIAT */ 1514e6a796c3SToby Isaac for (k = 0; k < npoints; ++k) { 151594e21283SToby Isaac PetscReal r = PetscCosReal(PETSC_PI * (1. - (4. * k + 3. + 2. * b) / (4. * npoints + 2. * (a + b + 1.)))), dP; 1516e6a796c3SToby Isaac PetscInt j; 1517e6a796c3SToby Isaac 1518e6a796c3SToby Isaac if (k > 0) r = 0.5 * (r + x[k - 1]); 1519e6a796c3SToby Isaac for (j = 0; j < maxIter; ++j) { 1520e6a796c3SToby Isaac PetscReal s = 0.0, delta, f, fp; 1521e6a796c3SToby Isaac PetscInt i; 1522e6a796c3SToby Isaac 1523e6a796c3SToby Isaac for (i = 0; i < k; ++i) s = s + 1.0 / (r - x[i]); 15249566063dSJacob Faibussowitsch PetscCall(PetscDTComputeJacobi(a, b, npoints, r, &f)); 15259566063dSJacob Faibussowitsch PetscCall(PetscDTComputeJacobiDerivative(a, b, npoints, r, 1, &fp)); 1526e6a796c3SToby Isaac delta = f / (fp - f * s); 1527e6a796c3SToby Isaac r = r - delta; 1528e6a796c3SToby Isaac if (PetscAbsReal(delta) < eps) break; 1529e6a796c3SToby Isaac } 1530e6a796c3SToby Isaac x[k] = r; 15319566063dSJacob Faibussowitsch PetscCall(PetscDTComputeJacobiDerivative(a, b, npoints, x[k], 1, &dP)); 1532e6a796c3SToby Isaac w[k] = a6 / (1.0 - PetscSqr(x[k])) / PetscSqr(dP); 1533e6a796c3SToby Isaac } 1534e6a796c3SToby Isaac PetscFunctionReturn(0); 1535e6a796c3SToby Isaac } 1536e6a796c3SToby Isaac 153794e21283SToby Isaac /* Compute the diagonals of the Jacobi matrix used in Golub & Welsch algorithms for Gauss-Jacobi 1538e6a796c3SToby Isaac * quadrature weight calculations on [-1,1] for exponents (1. + x)^a (1.-x)^b */ 1539*d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDTJacobiMatrix_Internal(PetscInt nPoints, PetscReal a, PetscReal b, PetscReal *d, PetscReal *s) 1540*d71ae5a4SJacob Faibussowitsch { 1541e6a796c3SToby Isaac PetscInt i; 1542e6a796c3SToby Isaac 1543e6a796c3SToby Isaac PetscFunctionBegin; 1544e6a796c3SToby Isaac for (i = 0; i < nPoints; i++) { 154594e21283SToby Isaac PetscReal A, B, C; 1546e6a796c3SToby Isaac 154794e21283SToby Isaac PetscDTJacobiRecurrence_Internal(i + 1, a, b, A, B, C); 154894e21283SToby Isaac d[i] = -A / B; 154994e21283SToby Isaac if (i) s[i - 1] *= C / B; 155094e21283SToby Isaac if (i < nPoints - 1) s[i] = 1. / B; 1551e6a796c3SToby Isaac } 1552e6a796c3SToby Isaac PetscFunctionReturn(0); 1553e6a796c3SToby Isaac } 1554e6a796c3SToby Isaac 1555*d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDTGaussJacobiQuadrature_GolubWelsch_Internal(PetscInt npoints, PetscReal a, PetscReal b, PetscReal *x, PetscReal *w) 1556*d71ae5a4SJacob Faibussowitsch { 1557e6a796c3SToby Isaac PetscReal mu0; 1558e6a796c3SToby Isaac PetscReal ga, gb, gab; 1559e6a796c3SToby Isaac PetscInt i; 1560e6a796c3SToby Isaac 1561e6a796c3SToby Isaac PetscFunctionBegin; 15629566063dSJacob Faibussowitsch PetscCall(PetscCitationsRegister(GolubWelschCitation, &GolubWelschCite)); 1563e6a796c3SToby Isaac 1564e6a796c3SToby Isaac #if defined(PETSC_HAVE_TGAMMA) 1565e6a796c3SToby Isaac ga = PetscTGamma(a + 1); 1566e6a796c3SToby Isaac gb = PetscTGamma(b + 1); 1567e6a796c3SToby Isaac gab = PetscTGamma(a + b + 2); 1568e6a796c3SToby Isaac #else 1569e6a796c3SToby Isaac { 1570e6a796c3SToby Isaac PetscInt ia, ib; 1571e6a796c3SToby Isaac 1572e6a796c3SToby Isaac ia = (PetscInt)a; 1573e6a796c3SToby Isaac ib = (PetscInt)b; 1574e6a796c3SToby Isaac if (ia == a && ib == b && ia + 1 > 0 && ib + 1 > 0 && ia + ib + 2 > 0) { /* All gamma(x) terms are (x-1)! terms */ 15759566063dSJacob Faibussowitsch PetscCall(PetscDTFactorial(ia, &ga)); 15769566063dSJacob Faibussowitsch PetscCall(PetscDTFactorial(ib, &gb)); 15779566063dSJacob Faibussowitsch PetscCall(PetscDTFactorial(ia + ib + 1, &gb)); 1578e6a796c3SToby Isaac } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "tgamma() - math routine is unavailable."); 1579e6a796c3SToby Isaac } 1580e6a796c3SToby Isaac #endif 1581e6a796c3SToby Isaac mu0 = PetscPowReal(2., a + b + 1.) * ga * gb / gab; 1582e6a796c3SToby Isaac 1583e6a796c3SToby Isaac #if defined(PETSCDTGAUSSIANQUADRATURE_EIG) 1584e6a796c3SToby Isaac { 1585e6a796c3SToby Isaac PetscReal *diag, *subdiag; 1586e6a796c3SToby Isaac PetscScalar *V; 1587e6a796c3SToby Isaac 15889566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(npoints, &diag, npoints, &subdiag)); 15899566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(npoints * npoints, &V)); 15909566063dSJacob Faibussowitsch PetscCall(PetscDTJacobiMatrix_Internal(npoints, a, b, diag, subdiag)); 1591e6a796c3SToby Isaac for (i = 0; i < npoints - 1; i++) subdiag[i] = PetscSqrtReal(subdiag[i]); 15929566063dSJacob Faibussowitsch PetscCall(PetscDTSymmetricTridiagonalEigensolve(npoints, diag, subdiag, x, V)); 159394e21283SToby Isaac for (i = 0; i < npoints; i++) w[i] = PetscSqr(PetscRealPart(V[i * npoints])) * mu0; 15949566063dSJacob Faibussowitsch PetscCall(PetscFree(V)); 15959566063dSJacob Faibussowitsch PetscCall(PetscFree2(diag, subdiag)); 1596e6a796c3SToby Isaac } 1597e6a796c3SToby Isaac #else 1598e6a796c3SToby Isaac SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "A LAPACK symmetric tridiagonal eigensolver could not be found"); 1599e6a796c3SToby Isaac #endif 160094e21283SToby Isaac { /* As of March 2, 2020, The Sun Performance Library breaks the LAPACK contract for xstegr and xsteqr: the 160194e21283SToby Isaac eigenvalues are not guaranteed to be in ascending order. So we heave a passive aggressive sigh and check that 160294e21283SToby Isaac the eigenvalues are sorted */ 160394e21283SToby Isaac PetscBool sorted; 160494e21283SToby Isaac 16059566063dSJacob Faibussowitsch PetscCall(PetscSortedReal(npoints, x, &sorted)); 160694e21283SToby Isaac if (!sorted) { 160794e21283SToby Isaac PetscInt *order, i; 160894e21283SToby Isaac PetscReal *tmp; 160994e21283SToby Isaac 16109566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(npoints, &order, npoints, &tmp)); 161194e21283SToby Isaac for (i = 0; i < npoints; i++) order[i] = i; 16129566063dSJacob Faibussowitsch PetscCall(PetscSortRealWithPermutation(npoints, x, order)); 16139566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(tmp, x, npoints)); 161494e21283SToby Isaac for (i = 0; i < npoints; i++) x[i] = tmp[order[i]]; 16159566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(tmp, w, npoints)); 161694e21283SToby Isaac for (i = 0; i < npoints; i++) w[i] = tmp[order[i]]; 16179566063dSJacob Faibussowitsch PetscCall(PetscFree2(order, tmp)); 161894e21283SToby Isaac } 161994e21283SToby Isaac } 1620e6a796c3SToby Isaac PetscFunctionReturn(0); 1621e6a796c3SToby Isaac } 1622e6a796c3SToby Isaac 1623*d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDTGaussJacobiQuadrature_Internal(PetscInt npoints, PetscReal alpha, PetscReal beta, PetscReal x[], PetscReal w[], PetscBool newton) 1624*d71ae5a4SJacob Faibussowitsch { 1625e6a796c3SToby Isaac PetscFunctionBegin; 162608401ef6SPierre Jolivet PetscCheck(npoints >= 1, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of points must be positive"); 1627e6a796c3SToby Isaac /* If asking for a 1D Lobatto point, just return the non-Lobatto 1D point */ 162808401ef6SPierre Jolivet PetscCheck(alpha > -1., PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "alpha must be > -1."); 162908401ef6SPierre Jolivet PetscCheck(beta > -1., PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "beta must be > -1."); 1630e6a796c3SToby Isaac 16311baa6e33SBarry Smith if (newton) PetscCall(PetscDTGaussJacobiQuadrature_Newton_Internal(npoints, alpha, beta, x, w)); 16321baa6e33SBarry Smith else PetscCall(PetscDTGaussJacobiQuadrature_GolubWelsch_Internal(npoints, alpha, beta, x, w)); 1633e6a796c3SToby Isaac if (alpha == beta) { /* symmetrize */ 1634e6a796c3SToby Isaac PetscInt i; 1635e6a796c3SToby Isaac for (i = 0; i < (npoints + 1) / 2; i++) { 1636e6a796c3SToby Isaac PetscInt j = npoints - 1 - i; 1637e6a796c3SToby Isaac PetscReal xi = x[i]; 1638e6a796c3SToby Isaac PetscReal xj = x[j]; 1639e6a796c3SToby Isaac PetscReal wi = w[i]; 1640e6a796c3SToby Isaac PetscReal wj = w[j]; 1641e6a796c3SToby Isaac 1642e6a796c3SToby Isaac x[i] = (xi - xj) / 2.; 1643e6a796c3SToby Isaac x[j] = (xj - xi) / 2.; 1644e6a796c3SToby Isaac w[i] = w[j] = (wi + wj) / 2.; 1645e6a796c3SToby Isaac } 1646e6a796c3SToby Isaac } 1647e6a796c3SToby Isaac PetscFunctionReturn(0); 1648e6a796c3SToby Isaac } 1649e6a796c3SToby Isaac 165094e21283SToby Isaac /*@ 165194e21283SToby Isaac PetscDTGaussJacobiQuadrature - quadrature for the interval [a, b] with the weight function 165294e21283SToby Isaac $(x-a)^\alpha (x-b)^\beta$. 165394e21283SToby Isaac 165494e21283SToby Isaac Not collective 165594e21283SToby Isaac 165694e21283SToby Isaac Input Parameters: 165794e21283SToby Isaac + npoints - the number of points in the quadrature rule 165894e21283SToby Isaac . a - the left endpoint of the interval 165994e21283SToby Isaac . b - the right endpoint of the interval 166094e21283SToby Isaac . alpha - the left exponent 166194e21283SToby Isaac - beta - the right exponent 166294e21283SToby Isaac 166394e21283SToby Isaac Output Parameters: 166494e21283SToby Isaac + x - array of length npoints, the locations of the quadrature points 166594e21283SToby Isaac - w - array of length npoints, the weights of the quadrature points 166694e21283SToby Isaac 166794e21283SToby Isaac Level: intermediate 166894e21283SToby Isaac 166994e21283SToby Isaac Note: this quadrature rule is exact for polynomials up to degree 2*npoints - 1. 167094e21283SToby Isaac @*/ 1671*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDTGaussJacobiQuadrature(PetscInt npoints, PetscReal a, PetscReal b, PetscReal alpha, PetscReal beta, PetscReal x[], PetscReal w[]) 1672*d71ae5a4SJacob Faibussowitsch { 167394e21283SToby Isaac PetscInt i; 1674e6a796c3SToby Isaac 1675e6a796c3SToby Isaac PetscFunctionBegin; 16769566063dSJacob Faibussowitsch PetscCall(PetscDTGaussJacobiQuadrature_Internal(npoints, alpha, beta, x, w, PetscDTGaussQuadratureNewton_Internal)); 167794e21283SToby Isaac if (a != -1. || b != 1.) { /* shift */ 167894e21283SToby Isaac for (i = 0; i < npoints; i++) { 167994e21283SToby Isaac x[i] = (x[i] + 1.) * ((b - a) / 2.) + a; 168094e21283SToby Isaac w[i] *= (b - a) / 2.; 168194e21283SToby Isaac } 168294e21283SToby Isaac } 1683e6a796c3SToby Isaac PetscFunctionReturn(0); 1684e6a796c3SToby Isaac } 1685e6a796c3SToby Isaac 1686*d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDTGaussLobattoJacobiQuadrature_Internal(PetscInt npoints, PetscReal alpha, PetscReal beta, PetscReal x[], PetscReal w[], PetscBool newton) 1687*d71ae5a4SJacob Faibussowitsch { 1688e6a796c3SToby Isaac PetscInt i; 1689e6a796c3SToby Isaac 1690e6a796c3SToby Isaac PetscFunctionBegin; 169108401ef6SPierre Jolivet PetscCheck(npoints >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of points must be positive"); 1692e6a796c3SToby Isaac /* If asking for a 1D Lobatto point, just return the non-Lobatto 1D point */ 169308401ef6SPierre Jolivet PetscCheck(alpha > -1., PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "alpha must be > -1."); 169408401ef6SPierre Jolivet PetscCheck(beta > -1., PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "beta must be > -1."); 1695e6a796c3SToby Isaac 1696e6a796c3SToby Isaac x[0] = -1.; 1697e6a796c3SToby Isaac x[npoints - 1] = 1.; 169848a46eb9SPierre Jolivet if (npoints > 2) PetscCall(PetscDTGaussJacobiQuadrature_Internal(npoints - 2, alpha + 1., beta + 1., &x[1], &w[1], newton)); 1699ad540459SPierre Jolivet for (i = 1; i < npoints - 1; i++) w[i] /= (1. - x[i] * x[i]); 17009566063dSJacob Faibussowitsch PetscCall(PetscDTGaussLobattoJacobiEndweights_Internal(npoints, alpha, beta, &w[0], &w[npoints - 1])); 1701e6a796c3SToby Isaac PetscFunctionReturn(0); 1702e6a796c3SToby Isaac } 1703e6a796c3SToby Isaac 170437045ce4SJed Brown /*@ 170594e21283SToby Isaac PetscDTGaussLobattoJacobiQuadrature - quadrature for the interval [a, b] with the weight function 170694e21283SToby Isaac $(x-a)^\alpha (x-b)^\beta$, with endpoints a and b included as quadrature points. 170794e21283SToby Isaac 170894e21283SToby Isaac Not collective 170994e21283SToby Isaac 171094e21283SToby Isaac Input Parameters: 171194e21283SToby Isaac + npoints - the number of points in the quadrature rule 171294e21283SToby Isaac . a - the left endpoint of the interval 171394e21283SToby Isaac . b - the right endpoint of the interval 171494e21283SToby Isaac . alpha - the left exponent 171594e21283SToby Isaac - beta - the right exponent 171694e21283SToby Isaac 171794e21283SToby Isaac Output Parameters: 171894e21283SToby Isaac + x - array of length npoints, the locations of the quadrature points 171994e21283SToby Isaac - w - array of length npoints, the weights of the quadrature points 172094e21283SToby Isaac 172194e21283SToby Isaac Level: intermediate 172294e21283SToby Isaac 172394e21283SToby Isaac Note: this quadrature rule is exact for polynomials up to degree 2*npoints - 3. 172494e21283SToby Isaac @*/ 1725*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDTGaussLobattoJacobiQuadrature(PetscInt npoints, PetscReal a, PetscReal b, PetscReal alpha, PetscReal beta, PetscReal x[], PetscReal w[]) 1726*d71ae5a4SJacob Faibussowitsch { 172794e21283SToby Isaac PetscInt i; 172894e21283SToby Isaac 172994e21283SToby Isaac PetscFunctionBegin; 17309566063dSJacob Faibussowitsch PetscCall(PetscDTGaussLobattoJacobiQuadrature_Internal(npoints, alpha, beta, x, w, PetscDTGaussQuadratureNewton_Internal)); 173194e21283SToby Isaac if (a != -1. || b != 1.) { /* shift */ 173294e21283SToby Isaac for (i = 0; i < npoints; i++) { 173394e21283SToby Isaac x[i] = (x[i] + 1.) * ((b - a) / 2.) + a; 173494e21283SToby Isaac w[i] *= (b - a) / 2.; 173594e21283SToby Isaac } 173694e21283SToby Isaac } 173794e21283SToby Isaac PetscFunctionReturn(0); 173894e21283SToby Isaac } 173994e21283SToby Isaac 174094e21283SToby Isaac /*@ 1741e6a796c3SToby Isaac PetscDTGaussQuadrature - create Gauss-Legendre quadrature 174237045ce4SJed Brown 174337045ce4SJed Brown Not Collective 174437045ce4SJed Brown 17454165533cSJose E. Roman Input Parameters: 174637045ce4SJed Brown + npoints - number of points 174737045ce4SJed Brown . a - left end of interval (often-1) 174837045ce4SJed Brown - b - right end of interval (often +1) 174937045ce4SJed Brown 17504165533cSJose E. Roman Output Parameters: 175137045ce4SJed Brown + x - quadrature points 175237045ce4SJed Brown - w - quadrature weights 175337045ce4SJed Brown 175437045ce4SJed Brown Level: intermediate 175537045ce4SJed Brown 175637045ce4SJed Brown References: 1757606c0280SSatish Balay . * - Golub and Welsch, Calculation of Quadrature Rules, Math. Comp. 23(106), 1969. 175837045ce4SJed Brown 1759db781477SPatrick Sanan .seealso: `PetscDTLegendreEval()` 176037045ce4SJed Brown @*/ 1761*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDTGaussQuadrature(PetscInt npoints, PetscReal a, PetscReal b, PetscReal *x, PetscReal *w) 1762*d71ae5a4SJacob Faibussowitsch { 176337045ce4SJed Brown PetscInt i; 176437045ce4SJed Brown 176537045ce4SJed Brown PetscFunctionBegin; 17669566063dSJacob Faibussowitsch PetscCall(PetscDTGaussJacobiQuadrature_Internal(npoints, 0., 0., x, w, PetscDTGaussQuadratureNewton_Internal)); 176794e21283SToby Isaac if (a != -1. || b != 1.) { /* shift */ 176837045ce4SJed Brown for (i = 0; i < npoints; i++) { 1769e6a796c3SToby Isaac x[i] = (x[i] + 1.) * ((b - a) / 2.) + a; 1770e6a796c3SToby Isaac w[i] *= (b - a) / 2.; 177137045ce4SJed Brown } 177237045ce4SJed Brown } 177337045ce4SJed Brown PetscFunctionReturn(0); 177437045ce4SJed Brown } 1775194825f6SJed Brown 17768272889dSSatish Balay /*@C 17778272889dSSatish Balay PetscDTGaussLobattoLegendreQuadrature - creates a set of the locations and weights of the Gauss-Lobatto-Legendre 17788272889dSSatish Balay nodes of a given size on the domain [-1,1] 17798272889dSSatish Balay 17808272889dSSatish Balay Not Collective 17818272889dSSatish Balay 1782d8d19677SJose E. Roman Input Parameters: 17838272889dSSatish Balay + n - number of grid nodes 1784f2e8fe4dShannah_mairs - type - PETSCGAUSSLOBATTOLEGENDRE_VIA_LINEAR_ALGEBRA or PETSCGAUSSLOBATTOLEGENDRE_VIA_NEWTON 17858272889dSSatish Balay 17864165533cSJose E. Roman Output Parameters: 17878272889dSSatish Balay + x - quadrature points 17888272889dSSatish Balay - w - quadrature weights 17898272889dSSatish Balay 17908272889dSSatish Balay Notes: 17918272889dSSatish Balay For n > 30 the Newton approach computes duplicate (incorrect) values for some nodes because the initial guess is apparently not 17928272889dSSatish Balay close enough to the desired solution 17938272889dSSatish Balay 17948272889dSSatish Balay These are useful for implementing spectral methods based on Gauss-Lobatto-Legendre (GLL) nodes 17958272889dSSatish Balay 1796a8d69d7bSBarry 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 17978272889dSSatish Balay 17988272889dSSatish Balay Level: intermediate 17998272889dSSatish Balay 1800db781477SPatrick Sanan .seealso: `PetscDTGaussQuadrature()` 18018272889dSSatish Balay 18028272889dSSatish Balay @*/ 1803*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDTGaussLobattoLegendreQuadrature(PetscInt npoints, PetscGaussLobattoLegendreCreateType type, PetscReal *x, PetscReal *w) 1804*d71ae5a4SJacob Faibussowitsch { 1805e6a796c3SToby Isaac PetscBool newton; 18068272889dSSatish Balay 18078272889dSSatish Balay PetscFunctionBegin; 180808401ef6SPierre Jolivet PetscCheck(npoints >= 2, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must provide at least 2 grid points per element"); 180994e21283SToby Isaac newton = (PetscBool)(type == PETSCGAUSSLOBATTOLEGENDRE_VIA_NEWTON); 18109566063dSJacob Faibussowitsch PetscCall(PetscDTGaussLobattoJacobiQuadrature_Internal(npoints, 0., 0., x, w, newton)); 18118272889dSSatish Balay PetscFunctionReturn(0); 18128272889dSSatish Balay } 18138272889dSSatish Balay 1814744bafbcSMatthew G. Knepley /*@ 1815744bafbcSMatthew G. Knepley PetscDTGaussTensorQuadrature - creates a tensor-product Gauss quadrature 1816744bafbcSMatthew G. Knepley 1817744bafbcSMatthew G. Knepley Not Collective 1818744bafbcSMatthew G. Knepley 18194165533cSJose E. Roman Input Parameters: 1820744bafbcSMatthew G. Knepley + dim - The spatial dimension 1821a6b92713SMatthew G. Knepley . Nc - The number of components 1822744bafbcSMatthew G. Knepley . npoints - number of points in one dimension 1823744bafbcSMatthew G. Knepley . a - left end of interval (often-1) 1824744bafbcSMatthew G. Knepley - b - right end of interval (often +1) 1825744bafbcSMatthew G. Knepley 18264165533cSJose E. Roman Output Parameter: 1827744bafbcSMatthew G. Knepley . q - A PetscQuadrature object 1828744bafbcSMatthew G. Knepley 1829744bafbcSMatthew G. Knepley Level: intermediate 1830744bafbcSMatthew G. Knepley 1831db781477SPatrick Sanan .seealso: `PetscDTGaussQuadrature()`, `PetscDTLegendreEval()` 1832744bafbcSMatthew G. Knepley @*/ 1833*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDTGaussTensorQuadrature(PetscInt dim, PetscInt Nc, PetscInt npoints, PetscReal a, PetscReal b, PetscQuadrature *q) 1834*d71ae5a4SJacob Faibussowitsch { 1835a6b92713SMatthew G. Knepley PetscInt totpoints = dim > 1 ? dim > 2 ? npoints * PetscSqr(npoints) : PetscSqr(npoints) : npoints, i, j, k, c; 1836744bafbcSMatthew G. Knepley PetscReal *x, *w, *xw, *ww; 1837744bafbcSMatthew G. Knepley 1838744bafbcSMatthew G. Knepley PetscFunctionBegin; 18399566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(totpoints * dim, &x)); 18409566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(totpoints * Nc, &w)); 1841744bafbcSMatthew G. Knepley /* Set up the Golub-Welsch system */ 1842744bafbcSMatthew G. Knepley switch (dim) { 1843744bafbcSMatthew G. Knepley case 0: 18449566063dSJacob Faibussowitsch PetscCall(PetscFree(x)); 18459566063dSJacob Faibussowitsch PetscCall(PetscFree(w)); 18469566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(1, &x)); 18479566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(Nc, &w)); 1848744bafbcSMatthew G. Knepley x[0] = 0.0; 1849a6b92713SMatthew G. Knepley for (c = 0; c < Nc; ++c) w[c] = 1.0; 1850744bafbcSMatthew G. Knepley break; 1851744bafbcSMatthew G. Knepley case 1: 18529566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(npoints, &ww)); 18539566063dSJacob Faibussowitsch PetscCall(PetscDTGaussQuadrature(npoints, a, b, x, ww)); 18549371c9d4SSatish Balay for (i = 0; i < npoints; ++i) 18559371c9d4SSatish Balay for (c = 0; c < Nc; ++c) w[i * Nc + c] = ww[i]; 18569566063dSJacob Faibussowitsch PetscCall(PetscFree(ww)); 1857744bafbcSMatthew G. Knepley break; 1858744bafbcSMatthew G. Knepley case 2: 18599566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(npoints, &xw, npoints, &ww)); 18609566063dSJacob Faibussowitsch PetscCall(PetscDTGaussQuadrature(npoints, a, b, xw, ww)); 1861744bafbcSMatthew G. Knepley for (i = 0; i < npoints; ++i) { 1862744bafbcSMatthew G. Knepley for (j = 0; j < npoints; ++j) { 1863744bafbcSMatthew G. Knepley x[(i * npoints + j) * dim + 0] = xw[i]; 1864744bafbcSMatthew G. Knepley x[(i * npoints + j) * dim + 1] = xw[j]; 1865a6b92713SMatthew G. Knepley for (c = 0; c < Nc; ++c) w[(i * npoints + j) * Nc + c] = ww[i] * ww[j]; 1866744bafbcSMatthew G. Knepley } 1867744bafbcSMatthew G. Knepley } 18689566063dSJacob Faibussowitsch PetscCall(PetscFree2(xw, ww)); 1869744bafbcSMatthew G. Knepley break; 1870744bafbcSMatthew G. Knepley case 3: 18719566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(npoints, &xw, npoints, &ww)); 18729566063dSJacob Faibussowitsch PetscCall(PetscDTGaussQuadrature(npoints, a, b, xw, ww)); 1873744bafbcSMatthew G. Knepley for (i = 0; i < npoints; ++i) { 1874744bafbcSMatthew G. Knepley for (j = 0; j < npoints; ++j) { 1875744bafbcSMatthew G. Knepley for (k = 0; k < npoints; ++k) { 1876744bafbcSMatthew G. Knepley x[((i * npoints + j) * npoints + k) * dim + 0] = xw[i]; 1877744bafbcSMatthew G. Knepley x[((i * npoints + j) * npoints + k) * dim + 1] = xw[j]; 1878744bafbcSMatthew G. Knepley x[((i * npoints + j) * npoints + k) * dim + 2] = xw[k]; 1879a6b92713SMatthew G. Knepley for (c = 0; c < Nc; ++c) w[((i * npoints + j) * npoints + k) * Nc + c] = ww[i] * ww[j] * ww[k]; 1880744bafbcSMatthew G. Knepley } 1881744bafbcSMatthew G. Knepley } 1882744bafbcSMatthew G. Knepley } 18839566063dSJacob Faibussowitsch PetscCall(PetscFree2(xw, ww)); 1884744bafbcSMatthew G. Knepley break; 1885*d71ae5a4SJacob Faibussowitsch default: 1886*d71ae5a4SJacob Faibussowitsch SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct quadrature rule for dimension %" PetscInt_FMT, dim); 1887744bafbcSMatthew G. Knepley } 18889566063dSJacob Faibussowitsch PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, q)); 18899566063dSJacob Faibussowitsch PetscCall(PetscQuadratureSetOrder(*q, 2 * npoints - 1)); 18909566063dSJacob Faibussowitsch PetscCall(PetscQuadratureSetData(*q, dim, Nc, totpoints, x, w)); 18919566063dSJacob Faibussowitsch PetscCall(PetscObjectChangeTypeName((PetscObject)*q, "GaussTensor")); 1892744bafbcSMatthew G. Knepley PetscFunctionReturn(0); 1893744bafbcSMatthew G. Knepley } 1894744bafbcSMatthew G. Knepley 1895f5f57ec0SBarry Smith /*@ 1896e6a796c3SToby Isaac PetscDTStroudConicalQuadrature - create Stroud conical quadrature for a simplex 1897494e7359SMatthew G. Knepley 1898494e7359SMatthew G. Knepley Not Collective 1899494e7359SMatthew G. Knepley 19004165533cSJose E. Roman Input Parameters: 1901494e7359SMatthew G. Knepley + dim - The simplex dimension 1902a6b92713SMatthew G. Knepley . Nc - The number of components 1903dcce0ee2SMatthew G. Knepley . npoints - The number of points in one dimension 1904494e7359SMatthew G. Knepley . a - left end of interval (often-1) 1905494e7359SMatthew G. Knepley - b - right end of interval (often +1) 1906494e7359SMatthew G. Knepley 19074165533cSJose E. Roman Output Parameter: 1908552aa4f7SMatthew G. Knepley . q - A PetscQuadrature object 1909494e7359SMatthew G. Knepley 1910494e7359SMatthew G. Knepley Level: intermediate 1911494e7359SMatthew G. Knepley 1912494e7359SMatthew G. Knepley References: 1913606c0280SSatish Balay . * - Karniadakis and Sherwin. FIAT 1914494e7359SMatthew G. Knepley 1915e6a796c3SToby Isaac Note: For dim == 1, this is Gauss-Legendre quadrature 1916e6a796c3SToby Isaac 1917db781477SPatrick Sanan .seealso: `PetscDTGaussTensorQuadrature()`, `PetscDTGaussQuadrature()` 1918494e7359SMatthew G. Knepley @*/ 1919*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDTStroudConicalQuadrature(PetscInt dim, PetscInt Nc, PetscInt npoints, PetscReal a, PetscReal b, PetscQuadrature *q) 1920*d71ae5a4SJacob Faibussowitsch { 1921fbdc3dfeSToby Isaac PetscInt totprev, totrem; 1922fbdc3dfeSToby Isaac PetscInt totpoints; 1923fbdc3dfeSToby Isaac PetscReal *p1, *w1; 1924fbdc3dfeSToby Isaac PetscReal *x, *w; 1925fbdc3dfeSToby Isaac PetscInt i, j, k, l, m, pt, c; 1926494e7359SMatthew G. Knepley 1927494e7359SMatthew G. Knepley PetscFunctionBegin; 192808401ef6SPierre Jolivet PetscCheck(!(a != -1.0) && !(b != 1.0), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must use default internal right now"); 1929fbdc3dfeSToby Isaac totpoints = 1; 1930fbdc3dfeSToby Isaac for (i = 0, totpoints = 1; i < dim; i++) totpoints *= npoints; 19319566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(totpoints * dim, &x)); 19329566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(totpoints * Nc, &w)); 19339566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(npoints, &p1, npoints, &w1)); 1934fbdc3dfeSToby Isaac for (i = 0; i < totpoints * Nc; i++) w[i] = 1.; 1935fbdc3dfeSToby Isaac for (i = 0, totprev = 1, totrem = totpoints / npoints; i < dim; i++) { 1936fbdc3dfeSToby Isaac PetscReal mul; 1937fbdc3dfeSToby Isaac 1938fbdc3dfeSToby Isaac mul = PetscPowReal(2., -i); 19399566063dSJacob Faibussowitsch PetscCall(PetscDTGaussJacobiQuadrature(npoints, -1., 1., i, 0.0, p1, w1)); 1940fbdc3dfeSToby Isaac for (pt = 0, l = 0; l < totprev; l++) { 1941fbdc3dfeSToby Isaac for (j = 0; j < npoints; j++) { 1942fbdc3dfeSToby Isaac for (m = 0; m < totrem; m++, pt++) { 1943fbdc3dfeSToby Isaac for (k = 0; k < i; k++) x[pt * dim + k] = (x[pt * dim + k] + 1.) * (1. - p1[j]) * 0.5 - 1.; 1944fbdc3dfeSToby Isaac x[pt * dim + i] = p1[j]; 1945fbdc3dfeSToby Isaac for (c = 0; c < Nc; c++) w[pt * Nc + c] *= mul * w1[j]; 1946494e7359SMatthew G. Knepley } 1947494e7359SMatthew G. Knepley } 1948494e7359SMatthew G. Knepley } 1949fbdc3dfeSToby Isaac totprev *= npoints; 1950fbdc3dfeSToby Isaac totrem /= npoints; 1951494e7359SMatthew G. Knepley } 19529566063dSJacob Faibussowitsch PetscCall(PetscFree2(p1, w1)); 19539566063dSJacob Faibussowitsch PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, q)); 19549566063dSJacob Faibussowitsch PetscCall(PetscQuadratureSetOrder(*q, 2 * npoints - 1)); 19559566063dSJacob Faibussowitsch PetscCall(PetscQuadratureSetData(*q, dim, Nc, totpoints, x, w)); 19569566063dSJacob Faibussowitsch PetscCall(PetscObjectChangeTypeName((PetscObject)*q, "StroudConical")); 1957494e7359SMatthew G. Knepley PetscFunctionReturn(0); 1958494e7359SMatthew G. Knepley } 1959494e7359SMatthew G. Knepley 1960d3c69ad0SToby Isaac static PetscBool MinSymTriQuadCite = PETSC_FALSE; 19619371c9d4SSatish Balay const char MinSymTriQuadCitation[] = "@article{WitherdenVincent2015,\n" 1962d3c69ad0SToby Isaac " title = {On the identification of symmetric quadrature rules for finite element methods},\n" 1963d3c69ad0SToby Isaac " journal = {Computers & Mathematics with Applications},\n" 1964d3c69ad0SToby Isaac " volume = {69},\n" 1965d3c69ad0SToby Isaac " number = {10},\n" 1966d3c69ad0SToby Isaac " pages = {1232-1241},\n" 1967d3c69ad0SToby Isaac " year = {2015},\n" 1968d3c69ad0SToby Isaac " issn = {0898-1221},\n" 1969d3c69ad0SToby Isaac " doi = {10.1016/j.camwa.2015.03.017},\n" 1970d3c69ad0SToby Isaac " url = {https://www.sciencedirect.com/science/article/pii/S0898122115001224},\n" 1971d3c69ad0SToby Isaac " author = {F.D. Witherden and P.E. Vincent},\n" 1972d3c69ad0SToby Isaac "}\n"; 1973d3c69ad0SToby Isaac 1974d3c69ad0SToby Isaac #include "petscdttriquadrules.h" 1975d3c69ad0SToby Isaac 1976d3c69ad0SToby Isaac static PetscBool MinSymTetQuadCite = PETSC_FALSE; 19779371c9d4SSatish Balay const char MinSymTetQuadCitation[] = "@article{JaskowiecSukumar2021\n" 1978d3c69ad0SToby Isaac " author = {Jaskowiec, Jan and Sukumar, N.},\n" 1979d3c69ad0SToby Isaac " title = {High-order symmetric cubature rules for tetrahedra and pyramids},\n" 1980d3c69ad0SToby Isaac " journal = {International Journal for Numerical Methods in Engineering},\n" 1981d3c69ad0SToby Isaac " volume = {122},\n" 1982d3c69ad0SToby Isaac " number = {1},\n" 1983d3c69ad0SToby Isaac " pages = {148-171},\n" 1984d3c69ad0SToby Isaac " doi = {10.1002/nme.6528},\n" 1985d3c69ad0SToby Isaac " url = {https://onlinelibrary.wiley.com/doi/abs/10.1002/nme.6528},\n" 1986d3c69ad0SToby Isaac " eprint = {https://onlinelibrary.wiley.com/doi/pdf/10.1002/nme.6528},\n" 1987d3c69ad0SToby Isaac " year = {2021}\n" 1988d3c69ad0SToby Isaac "}\n"; 1989d3c69ad0SToby Isaac 1990d3c69ad0SToby Isaac #include "petscdttetquadrules.h" 1991d3c69ad0SToby Isaac 1992d3c69ad0SToby Isaac // https://en.wikipedia.org/wiki/Partition_(number_theory) 1993*d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDTPartitionNumber(PetscInt n, PetscInt *p) 1994*d71ae5a4SJacob Faibussowitsch { 1995d3c69ad0SToby Isaac // sequence A000041 in the OEIS 1996d3c69ad0SToby 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}; 1997d3c69ad0SToby Isaac PetscInt tabulated_max = PETSC_STATIC_ARRAY_LENGTH(partition) - 1; 1998d3c69ad0SToby Isaac 1999d3c69ad0SToby Isaac PetscFunctionBegin; 2000d3c69ad0SToby Isaac PetscCheck(n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Partition number not defined for negative number %" PetscInt_FMT, n); 2001d3c69ad0SToby Isaac // not implementing the pentagonal number recurrence, we don't need partition numbers for n that high 2002d3c69ad0SToby 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); 2003d3c69ad0SToby Isaac *p = partition[n]; 2004d3c69ad0SToby Isaac PetscFunctionReturn(0); 2005d3c69ad0SToby Isaac } 2006d3c69ad0SToby Isaac 2007d3c69ad0SToby Isaac /*@ 2008d3c69ad0SToby Isaac PetscDTSimplexQuadrature - Create a quadrature rule for a simplex that exactly integrates polynomials up to a given degree. 2009d3c69ad0SToby Isaac 2010d3c69ad0SToby Isaac Not Collective 2011d3c69ad0SToby Isaac 2012d3c69ad0SToby Isaac Input Parameters: 2013d3c69ad0SToby Isaac + dim - The spatial dimension of the simplex (1 = segment, 2 = triangle, 3 = tetrahedron) 2014d3c69ad0SToby Isaac . degree - The largest polynomial degree that is required to be integrated exactly 2015d3c69ad0SToby Isaac - type - left end of interval (often-1) 2016d3c69ad0SToby Isaac 2017d3c69ad0SToby Isaac Output Parameter: 2018d3c69ad0SToby Isaac . quad - A PetscQuadrature object for integration over the biunit simplex 2019d3c69ad0SToby Isaac (defined by the bounds $x_i >= -1$ and $\sum_i x_i <= 2 - d$) that is exact for 2020d3c69ad0SToby Isaac polynomials up to the given degree 2021d3c69ad0SToby Isaac 2022d3c69ad0SToby Isaac Level: intermediate 2023d3c69ad0SToby Isaac 2024d3c69ad0SToby Isaac .seealso: `PetscDTSimplexQuadratureType`, `PetscDTGaussQuadrature()`, `PetscDTStroudCononicalQuadrature()` 2025d3c69ad0SToby Isaac @*/ 2026*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDTSimplexQuadrature(PetscInt dim, PetscInt degree, PetscDTSimplexQuadratureType type, PetscQuadrature *quad) 2027*d71ae5a4SJacob Faibussowitsch { 2028d3c69ad0SToby Isaac PetscDTSimplexQuadratureType orig_type = type; 2029d3c69ad0SToby Isaac 2030d3c69ad0SToby Isaac PetscFunctionBegin; 2031d3c69ad0SToby Isaac PetscCheck(dim >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Negative dimension %" PetscInt_FMT, dim); 2032d3c69ad0SToby Isaac PetscCheck(degree >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Negative degree %" PetscInt_FMT, degree); 2033ad540459SPierre Jolivet if (type == PETSCDTSIMPLEXQUAD_DEFAULT) type = PETSCDTSIMPLEXQUAD_MINSYM; 2034d3c69ad0SToby Isaac if (type == PETSCDTSIMPLEXQUAD_CONIC || dim < 2) { 2035d3c69ad0SToby Isaac PetscInt points_per_dim = (degree + 2) / 2; // ceil((degree + 1) / 2); 2036d3c69ad0SToby Isaac PetscCall(PetscDTStroudConicalQuadrature(dim, 1, points_per_dim, -1, 1, quad)); 2037d3c69ad0SToby Isaac } else { 2038d3c69ad0SToby Isaac PetscInt n = dim + 1; 2039d3c69ad0SToby Isaac PetscInt fact = 1; 2040d3c69ad0SToby Isaac PetscInt *part, *perm; 2041d3c69ad0SToby Isaac PetscInt p = 0; 2042d3c69ad0SToby Isaac PetscInt max_degree; 2043d3c69ad0SToby Isaac const PetscInt *nodes_per_type = NULL; 2044d3c69ad0SToby Isaac const PetscInt *all_num_full_nodes = NULL; 2045d3c69ad0SToby Isaac const PetscReal **weights_list = NULL; 2046d3c69ad0SToby Isaac const PetscReal **compact_nodes_list = NULL; 2047d3c69ad0SToby Isaac const char *citation = NULL; 2048d3c69ad0SToby Isaac PetscBool *cited = NULL; 2049d3c69ad0SToby Isaac 2050d3c69ad0SToby Isaac switch (dim) { 2051d3c69ad0SToby Isaac case 2: 2052d3c69ad0SToby Isaac cited = &MinSymTriQuadCite; 2053d3c69ad0SToby Isaac citation = MinSymTriQuadCitation; 2054d3c69ad0SToby Isaac max_degree = PetscDTWVTriQuad_max_degree; 2055d3c69ad0SToby Isaac nodes_per_type = PetscDTWVTriQuad_num_orbits; 2056d3c69ad0SToby Isaac all_num_full_nodes = PetscDTWVTriQuad_num_nodes; 2057d3c69ad0SToby Isaac weights_list = PetscDTWVTriQuad_weights; 2058d3c69ad0SToby Isaac compact_nodes_list = PetscDTWVTriQuad_orbits; 2059d3c69ad0SToby Isaac break; 2060d3c69ad0SToby Isaac case 3: 2061d3c69ad0SToby Isaac cited = &MinSymTetQuadCite; 2062d3c69ad0SToby Isaac citation = MinSymTetQuadCitation; 2063d3c69ad0SToby Isaac max_degree = PetscDTJSTetQuad_max_degree; 2064d3c69ad0SToby Isaac nodes_per_type = PetscDTJSTetQuad_num_orbits; 2065d3c69ad0SToby Isaac all_num_full_nodes = PetscDTJSTetQuad_num_nodes; 2066d3c69ad0SToby Isaac weights_list = PetscDTJSTetQuad_weights; 2067d3c69ad0SToby Isaac compact_nodes_list = PetscDTJSTetQuad_orbits; 2068d3c69ad0SToby Isaac break; 2069*d71ae5a4SJacob Faibussowitsch default: 2070*d71ae5a4SJacob Faibussowitsch max_degree = -1; 2071*d71ae5a4SJacob Faibussowitsch break; 2072d3c69ad0SToby Isaac } 2073d3c69ad0SToby Isaac 2074d3c69ad0SToby Isaac if (degree > max_degree) { 2075d3c69ad0SToby Isaac if (orig_type == PETSCDTSIMPLEXQUAD_DEFAULT) { 2076d3c69ad0SToby Isaac // fall back to conic 2077d3c69ad0SToby Isaac PetscCall(PetscDTSimplexQuadrature(dim, degree, PETSCDTSIMPLEXQUAD_CONIC, quad)); 2078d3c69ad0SToby Isaac PetscFunctionReturn(0); 2079d3c69ad0SToby Isaac } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Minimal symmetric quadrature for dim %" PetscInt_FMT ", degree %" PetscInt_FMT " unsupported", dim, degree); 2080d3c69ad0SToby Isaac } 2081d3c69ad0SToby Isaac 2082d3c69ad0SToby Isaac PetscCall(PetscCitationsRegister(citation, cited)); 2083d3c69ad0SToby Isaac 2084d3c69ad0SToby Isaac PetscCall(PetscDTPartitionNumber(n, &p)); 2085d3c69ad0SToby Isaac for (PetscInt d = 2; d <= n; d++) fact *= d; 2086d3c69ad0SToby Isaac 2087d3c69ad0SToby Isaac PetscInt num_full_nodes = all_num_full_nodes[degree]; 2088d3c69ad0SToby Isaac const PetscReal *all_compact_nodes = compact_nodes_list[degree]; 2089d3c69ad0SToby Isaac const PetscReal *all_compact_weights = weights_list[degree]; 2090d3c69ad0SToby Isaac nodes_per_type = &nodes_per_type[p * degree]; 2091d3c69ad0SToby Isaac 2092d3c69ad0SToby Isaac PetscReal *points; 2093d3c69ad0SToby Isaac PetscReal *counts; 2094d3c69ad0SToby Isaac PetscReal *weights; 2095d3c69ad0SToby Isaac PetscReal *bary_to_biunit; // row-major transformation of barycentric coordinate to biunit 2096d3c69ad0SToby Isaac PetscQuadrature q; 2097d3c69ad0SToby Isaac 2098d3c69ad0SToby Isaac // compute the transformation 2099d3c69ad0SToby Isaac PetscCall(PetscMalloc1(n * dim, &bary_to_biunit)); 2100d3c69ad0SToby Isaac for (PetscInt d = 0; d < dim; d++) { 2101ad540459SPierre Jolivet for (PetscInt b = 0; b < n; b++) bary_to_biunit[d * n + b] = (d == b) ? 1.0 : -1.0; 2102d3c69ad0SToby Isaac } 2103d3c69ad0SToby Isaac 2104d3c69ad0SToby Isaac PetscCall(PetscMalloc3(n, &part, n, &perm, n, &counts)); 2105d3c69ad0SToby Isaac PetscCall(PetscCalloc1(num_full_nodes * dim, &points)); 2106d3c69ad0SToby Isaac PetscCall(PetscMalloc1(num_full_nodes, &weights)); 2107d3c69ad0SToby Isaac 2108d3c69ad0SToby Isaac // (0, 0, ...) is the first partition lexicographically 2109d3c69ad0SToby Isaac PetscCall(PetscArrayzero(part, n)); 2110d3c69ad0SToby Isaac PetscCall(PetscArrayzero(counts, n)); 2111d3c69ad0SToby Isaac counts[0] = n; 2112d3c69ad0SToby Isaac 2113d3c69ad0SToby Isaac // for each partition 2114d3c69ad0SToby Isaac for (PetscInt s = 0, node_offset = 0; s < p; s++) { 2115d3c69ad0SToby Isaac PetscInt num_compact_coords = part[n - 1] + 1; 2116d3c69ad0SToby Isaac 2117d3c69ad0SToby Isaac const PetscReal *compact_nodes = all_compact_nodes; 2118d3c69ad0SToby Isaac const PetscReal *compact_weights = all_compact_weights; 2119d3c69ad0SToby Isaac all_compact_nodes += num_compact_coords * nodes_per_type[s]; 2120d3c69ad0SToby Isaac all_compact_weights += nodes_per_type[s]; 2121d3c69ad0SToby Isaac 2122d3c69ad0SToby Isaac // for every permutation of the vertices 2123d3c69ad0SToby Isaac for (PetscInt f = 0; f < fact; f++) { 2124d3c69ad0SToby Isaac PetscCall(PetscDTEnumPerm(n, f, perm, NULL)); 2125d3c69ad0SToby Isaac 2126d3c69ad0SToby Isaac // check if it is a valid permutation 2127d3c69ad0SToby Isaac PetscInt digit; 2128d3c69ad0SToby Isaac for (digit = 1; digit < n; digit++) { 2129d3c69ad0SToby Isaac // skip permutations that would duplicate a node because it has a smaller symmetry group 2130d3c69ad0SToby Isaac if (part[digit - 1] == part[digit] && perm[digit - 1] > perm[digit]) break; 2131d3c69ad0SToby Isaac } 2132d3c69ad0SToby Isaac if (digit < n) continue; 2133d3c69ad0SToby Isaac 2134d3c69ad0SToby Isaac // create full nodes from this permutation of the compact nodes 2135d3c69ad0SToby Isaac PetscReal *full_nodes = &points[node_offset * dim]; 2136d3c69ad0SToby Isaac PetscReal *full_weights = &weights[node_offset]; 2137d3c69ad0SToby Isaac 2138d3c69ad0SToby Isaac PetscCall(PetscArraycpy(full_weights, compact_weights, nodes_per_type[s])); 2139d3c69ad0SToby Isaac for (PetscInt b = 0; b < n; b++) { 2140d3c69ad0SToby Isaac for (PetscInt d = 0; d < dim; d++) { 2141ad540459SPierre Jolivet 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]]; 2142d3c69ad0SToby Isaac } 2143d3c69ad0SToby Isaac } 2144d3c69ad0SToby Isaac node_offset += nodes_per_type[s]; 2145d3c69ad0SToby Isaac } 2146d3c69ad0SToby Isaac 2147d3c69ad0SToby Isaac if (s < p - 1) { // Generate the next partition 2148d3c69ad0SToby Isaac /* A partition is described by the number of coordinates that are in 2149d3c69ad0SToby Isaac * each set of duplicates (counts) and redundantly by mapping each 2150d3c69ad0SToby Isaac * index to its set of duplicates (part) 2151d3c69ad0SToby Isaac * 2152d3c69ad0SToby Isaac * Counts should always be in nonincreasing order 2153d3c69ad0SToby Isaac * 2154d3c69ad0SToby Isaac * We want to generate the partitions lexically by part, which means 2155d3c69ad0SToby Isaac * finding the last index where count > 1 and reducing by 1. 2156d3c69ad0SToby Isaac * 2157d3c69ad0SToby Isaac * For the new counts beyond that index, we eagerly assign the remaining 2158d3c69ad0SToby Isaac * capacity of the partition to smaller indices (ensures lexical ordering), 2159d3c69ad0SToby Isaac * while respecting the nonincreasing invariant of the counts 2160d3c69ad0SToby Isaac */ 2161d3c69ad0SToby Isaac PetscInt last_digit = part[n - 1]; 2162d3c69ad0SToby Isaac PetscInt last_digit_with_extra = last_digit; 2163d3c69ad0SToby Isaac while (counts[last_digit_with_extra] == 1) last_digit_with_extra--; 2164d3c69ad0SToby Isaac PetscInt limit = --counts[last_digit_with_extra]; 2165d3c69ad0SToby Isaac PetscInt total_to_distribute = last_digit - last_digit_with_extra + 1; 2166d3c69ad0SToby Isaac for (PetscInt digit = last_digit_with_extra + 1; digit < n; digit++) { 2167d3c69ad0SToby Isaac counts[digit] = PetscMin(limit, total_to_distribute); 2168d3c69ad0SToby Isaac total_to_distribute -= PetscMin(limit, total_to_distribute); 2169d3c69ad0SToby Isaac } 2170d3c69ad0SToby Isaac for (PetscInt digit = 0, offset = 0; digit < n; digit++) { 2171d3c69ad0SToby Isaac PetscInt count = counts[digit]; 2172ad540459SPierre Jolivet for (PetscInt c = 0; c < count; c++) part[offset++] = digit; 2173d3c69ad0SToby Isaac } 2174d3c69ad0SToby Isaac } 2175d3c69ad0SToby Isaac } 2176d3c69ad0SToby Isaac PetscCall(PetscFree3(part, perm, counts)); 2177d3c69ad0SToby Isaac PetscCall(PetscFree(bary_to_biunit)); 2178d3c69ad0SToby Isaac PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, &q)); 2179d3c69ad0SToby Isaac PetscCall(PetscQuadratureSetData(q, dim, 1, num_full_nodes, points, weights)); 2180d3c69ad0SToby Isaac *quad = q; 2181d3c69ad0SToby Isaac } 2182d3c69ad0SToby Isaac PetscFunctionReturn(0); 2183d3c69ad0SToby Isaac } 2184d3c69ad0SToby Isaac 2185f5f57ec0SBarry Smith /*@ 2186b3c0f97bSTom Klotz PetscDTTanhSinhTensorQuadrature - create tanh-sinh quadrature for a tensor product cell 2187b3c0f97bSTom Klotz 2188b3c0f97bSTom Klotz Not Collective 2189b3c0f97bSTom Klotz 21904165533cSJose E. Roman Input Parameters: 2191b3c0f97bSTom Klotz + dim - The cell dimension 2192b3c0f97bSTom Klotz . level - The number of points in one dimension, 2^l 2193b3c0f97bSTom Klotz . a - left end of interval (often-1) 2194b3c0f97bSTom Klotz - b - right end of interval (often +1) 2195b3c0f97bSTom Klotz 21964165533cSJose E. Roman Output Parameter: 2197b3c0f97bSTom Klotz . q - A PetscQuadrature object 2198b3c0f97bSTom Klotz 2199b3c0f97bSTom Klotz Level: intermediate 2200b3c0f97bSTom Klotz 2201db781477SPatrick Sanan .seealso: `PetscDTGaussTensorQuadrature()` 2202b3c0f97bSTom Klotz @*/ 2203*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDTTanhSinhTensorQuadrature(PetscInt dim, PetscInt level, PetscReal a, PetscReal b, PetscQuadrature *q) 2204*d71ae5a4SJacob Faibussowitsch { 2205b3c0f97bSTom Klotz const PetscInt p = 16; /* Digits of precision in the evaluation */ 2206b3c0f97bSTom Klotz const PetscReal alpha = (b - a) / 2.; /* Half-width of the integration interval */ 2207b3c0f97bSTom Klotz const PetscReal beta = (b + a) / 2.; /* Center of the integration interval */ 2208b3c0f97bSTom Klotz const PetscReal h = PetscPowReal(2.0, -level); /* Step size, length between x_k */ 2209d84b4d08SMatthew G. Knepley PetscReal xk; /* Quadrature point x_k on reference domain [-1, 1] */ 2210b3c0f97bSTom Klotz PetscReal wk = 0.5 * PETSC_PI; /* Quadrature weight at x_k */ 2211b3c0f97bSTom Klotz PetscReal *x, *w; 2212b3c0f97bSTom Klotz PetscInt K, k, npoints; 2213b3c0f97bSTom Klotz 2214b3c0f97bSTom Klotz PetscFunctionBegin; 221563a3b9bcSJacob Faibussowitsch PetscCheck(dim <= 1, PETSC_COMM_SELF, PETSC_ERR_SUP, "Dimension %" PetscInt_FMT " not yet implemented", dim); 221628b400f6SJacob Faibussowitsch PetscCheck(level, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must give a number of significant digits"); 2217b3c0f97bSTom Klotz /* Find K such that the weights are < 32 digits of precision */ 2218ad540459SPierre Jolivet 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))); 22199566063dSJacob Faibussowitsch PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, q)); 22209566063dSJacob Faibussowitsch PetscCall(PetscQuadratureSetOrder(*q, 2 * K + 1)); 2221b3c0f97bSTom Klotz npoints = 2 * K - 1; 22229566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(npoints * dim, &x)); 22239566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(npoints, &w)); 2224b3c0f97bSTom Klotz /* Center term */ 2225b3c0f97bSTom Klotz x[0] = beta; 2226b3c0f97bSTom Klotz w[0] = 0.5 * alpha * PETSC_PI; 2227b3c0f97bSTom Klotz for (k = 1; k < K; ++k) { 22289add2064SThomas Klotz wk = 0.5 * alpha * h * PETSC_PI * PetscCoshReal(k * h) / PetscSqr(PetscCoshReal(0.5 * PETSC_PI * PetscSinhReal(k * h))); 22291118d4bcSLisandro Dalcin xk = PetscTanhReal(0.5 * PETSC_PI * PetscSinhReal(k * h)); 2230b3c0f97bSTom Klotz x[2 * k - 1] = -alpha * xk + beta; 2231b3c0f97bSTom Klotz w[2 * k - 1] = wk; 2232b3c0f97bSTom Klotz x[2 * k + 0] = alpha * xk + beta; 2233b3c0f97bSTom Klotz w[2 * k + 0] = wk; 2234b3c0f97bSTom Klotz } 22359566063dSJacob Faibussowitsch PetscCall(PetscQuadratureSetData(*q, dim, 1, npoints, x, w)); 2236b3c0f97bSTom Klotz PetscFunctionReturn(0); 2237b3c0f97bSTom Klotz } 2238b3c0f97bSTom Klotz 2239*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDTTanhSinhIntegrate(void (*func)(const PetscReal[], void *, PetscReal *), PetscReal a, PetscReal b, PetscInt digits, void *ctx, PetscReal *sol) 2240*d71ae5a4SJacob Faibussowitsch { 2241b3c0f97bSTom Klotz const PetscInt p = 16; /* Digits of precision in the evaluation */ 2242b3c0f97bSTom Klotz const PetscReal alpha = (b - a) / 2.; /* Half-width of the integration interval */ 2243b3c0f97bSTom Klotz const PetscReal beta = (b + a) / 2.; /* Center of the integration interval */ 2244b3c0f97bSTom Klotz PetscReal h = 1.0; /* Step size, length between x_k */ 2245b3c0f97bSTom Klotz PetscInt l = 0; /* Level of refinement, h = 2^{-l} */ 2246b3c0f97bSTom Klotz PetscReal osum = 0.0; /* Integral on last level */ 2247b3c0f97bSTom Klotz PetscReal psum = 0.0; /* Integral on the level before the last level */ 2248b3c0f97bSTom Klotz PetscReal sum; /* Integral on current level */ 2249446c295cSMatthew G. Knepley PetscReal yk; /* Quadrature point 1 - x_k on reference domain [-1, 1] */ 2250b3c0f97bSTom Klotz PetscReal lx, rx; /* Quadrature points to the left and right of 0 on the real domain [a, b] */ 2251b3c0f97bSTom Klotz PetscReal wk; /* Quadrature weight at x_k */ 2252b3c0f97bSTom Klotz PetscReal lval, rval; /* Terms in the quadature sum to the left and right of 0 */ 2253b3c0f97bSTom Klotz PetscInt d; /* Digits of precision in the integral */ 2254b3c0f97bSTom Klotz 2255b3c0f97bSTom Klotz PetscFunctionBegin; 225608401ef6SPierre Jolivet PetscCheck(digits > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must give a positive number of significant digits"); 2257b3c0f97bSTom Klotz /* Center term */ 2258d6685f55SMatthew G. Knepley func(&beta, ctx, &lval); 2259b3c0f97bSTom Klotz sum = 0.5 * alpha * PETSC_PI * lval; 2260b3c0f97bSTom Klotz /* */ 2261b3c0f97bSTom Klotz do { 2262b3c0f97bSTom Klotz PetscReal lterm, rterm, maxTerm = 0.0, d1, d2, d3, d4; 2263b3c0f97bSTom Klotz PetscInt k = 1; 2264b3c0f97bSTom Klotz 2265b3c0f97bSTom Klotz ++l; 226663a3b9bcSJacob Faibussowitsch /* PetscPrintf(PETSC_COMM_SELF, "LEVEL %" PetscInt_FMT " sum: %15.15f\n", l, sum); */ 2267b3c0f97bSTom Klotz /* At each level of refinement, h --> h/2 and sum --> sum/2 */ 2268b3c0f97bSTom Klotz psum = osum; 2269b3c0f97bSTom Klotz osum = sum; 2270b3c0f97bSTom Klotz h *= 0.5; 2271b3c0f97bSTom Klotz sum *= 0.5; 2272b3c0f97bSTom Klotz do { 22739add2064SThomas Klotz wk = 0.5 * h * PETSC_PI * PetscCoshReal(k * h) / PetscSqr(PetscCoshReal(0.5 * PETSC_PI * PetscSinhReal(k * h))); 2274446c295cSMatthew G. Knepley yk = 1.0 / (PetscExpReal(0.5 * PETSC_PI * PetscSinhReal(k * h)) * PetscCoshReal(0.5 * PETSC_PI * PetscSinhReal(k * h))); 2275446c295cSMatthew G. Knepley lx = -alpha * (1.0 - yk) + beta; 2276446c295cSMatthew G. Knepley rx = alpha * (1.0 - yk) + beta; 2277d6685f55SMatthew G. Knepley func(&lx, ctx, &lval); 2278d6685f55SMatthew G. Knepley func(&rx, ctx, &rval); 2279b3c0f97bSTom Klotz lterm = alpha * wk * lval; 2280b3c0f97bSTom Klotz maxTerm = PetscMax(PetscAbsReal(lterm), maxTerm); 2281b3c0f97bSTom Klotz sum += lterm; 2282b3c0f97bSTom Klotz rterm = alpha * wk * rval; 2283b3c0f97bSTom Klotz maxTerm = PetscMax(PetscAbsReal(rterm), maxTerm); 2284b3c0f97bSTom Klotz sum += rterm; 2285b3c0f97bSTom Klotz ++k; 2286b3c0f97bSTom Klotz /* Only need to evaluate every other point on refined levels */ 2287b3c0f97bSTom Klotz if (l != 1) ++k; 22889add2064SThomas Klotz } while (PetscAbsReal(PetscLog10Real(wk)) < p); /* Only need to evaluate sum until weights are < 32 digits of precision */ 2289b3c0f97bSTom Klotz 2290b3c0f97bSTom Klotz d1 = PetscLog10Real(PetscAbsReal(sum - osum)); 2291b3c0f97bSTom Klotz d2 = PetscLog10Real(PetscAbsReal(sum - psum)); 2292b3c0f97bSTom Klotz d3 = PetscLog10Real(maxTerm) - p; 229309d48545SBarry Smith if (PetscMax(PetscAbsReal(lterm), PetscAbsReal(rterm)) == 0.0) d4 = 0.0; 229409d48545SBarry Smith else d4 = PetscLog10Real(PetscMax(PetscAbsReal(lterm), PetscAbsReal(rterm))); 2295b3c0f97bSTom Klotz d = PetscAbsInt(PetscMin(0, PetscMax(PetscMax(PetscMax(PetscSqr(d1) / d2, 2 * d1), d3), d4))); 22969add2064SThomas Klotz } while (d < digits && l < 12); 2297b3c0f97bSTom Klotz *sol = sum; 2298e510cb1fSThomas Klotz 2299b3c0f97bSTom Klotz PetscFunctionReturn(0); 2300b3c0f97bSTom Klotz } 2301b3c0f97bSTom Klotz 2302497880caSRichard Tran Mills #if defined(PETSC_HAVE_MPFR) 2303*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDTTanhSinhIntegrateMPFR(void (*func)(const PetscReal[], void *, PetscReal *), PetscReal a, PetscReal b, PetscInt digits, void *ctx, PetscReal *sol) 2304*d71ae5a4SJacob Faibussowitsch { 2305e510cb1fSThomas Klotz const PetscInt safetyFactor = 2; /* Calculate abcissa until 2*p digits */ 230629f144ccSMatthew G. Knepley PetscInt l = 0; /* Level of refinement, h = 2^{-l} */ 230729f144ccSMatthew G. Knepley mpfr_t alpha; /* Half-width of the integration interval */ 230829f144ccSMatthew G. Knepley mpfr_t beta; /* Center of the integration interval */ 230929f144ccSMatthew G. Knepley mpfr_t h; /* Step size, length between x_k */ 231029f144ccSMatthew G. Knepley mpfr_t osum; /* Integral on last level */ 231129f144ccSMatthew G. Knepley mpfr_t psum; /* Integral on the level before the last level */ 231229f144ccSMatthew G. Knepley mpfr_t sum; /* Integral on current level */ 231329f144ccSMatthew G. Knepley mpfr_t yk; /* Quadrature point 1 - x_k on reference domain [-1, 1] */ 231429f144ccSMatthew G. Knepley mpfr_t lx, rx; /* Quadrature points to the left and right of 0 on the real domain [a, b] */ 231529f144ccSMatthew G. Knepley mpfr_t wk; /* Quadrature weight at x_k */ 23161fbc92bbSMatthew G. Knepley PetscReal lval, rval, rtmp; /* Terms in the quadature sum to the left and right of 0 */ 231729f144ccSMatthew G. Knepley PetscInt d; /* Digits of precision in the integral */ 231829f144ccSMatthew G. Knepley mpfr_t pi2, kh, msinh, mcosh, maxTerm, curTerm, tmp; 231929f144ccSMatthew G. Knepley 232029f144ccSMatthew G. Knepley PetscFunctionBegin; 232108401ef6SPierre Jolivet PetscCheck(digits > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must give a positive number of significant digits"); 232229f144ccSMatthew G. Knepley /* Create high precision storage */ 2323c9f744b5SMatthew 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); 232429f144ccSMatthew G. Knepley /* Initialization */ 232529f144ccSMatthew G. Knepley mpfr_set_d(alpha, 0.5 * (b - a), MPFR_RNDN); 232629f144ccSMatthew G. Knepley mpfr_set_d(beta, 0.5 * (b + a), MPFR_RNDN); 232729f144ccSMatthew G. Knepley mpfr_set_d(osum, 0.0, MPFR_RNDN); 232829f144ccSMatthew G. Knepley mpfr_set_d(psum, 0.0, MPFR_RNDN); 232929f144ccSMatthew G. Knepley mpfr_set_d(h, 1.0, MPFR_RNDN); 233029f144ccSMatthew G. Knepley mpfr_const_pi(pi2, MPFR_RNDN); 233129f144ccSMatthew G. Knepley mpfr_mul_d(pi2, pi2, 0.5, MPFR_RNDN); 233229f144ccSMatthew G. Knepley /* Center term */ 23331fbc92bbSMatthew G. Knepley rtmp = 0.5 * (b + a); 23341fbc92bbSMatthew G. Knepley func(&rtmp, ctx, &lval); 233529f144ccSMatthew G. Knepley mpfr_set(sum, pi2, MPFR_RNDN); 233629f144ccSMatthew G. Knepley mpfr_mul(sum, sum, alpha, MPFR_RNDN); 233729f144ccSMatthew G. Knepley mpfr_mul_d(sum, sum, lval, MPFR_RNDN); 233829f144ccSMatthew G. Knepley /* */ 233929f144ccSMatthew G. Knepley do { 234029f144ccSMatthew G. Knepley PetscReal d1, d2, d3, d4; 234129f144ccSMatthew G. Knepley PetscInt k = 1; 234229f144ccSMatthew G. Knepley 234329f144ccSMatthew G. Knepley ++l; 234429f144ccSMatthew G. Knepley mpfr_set_d(maxTerm, 0.0, MPFR_RNDN); 234563a3b9bcSJacob Faibussowitsch /* PetscPrintf(PETSC_COMM_SELF, "LEVEL %" PetscInt_FMT " sum: %15.15f\n", l, sum); */ 234629f144ccSMatthew G. Knepley /* At each level of refinement, h --> h/2 and sum --> sum/2 */ 234729f144ccSMatthew G. Knepley mpfr_set(psum, osum, MPFR_RNDN); 234829f144ccSMatthew G. Knepley mpfr_set(osum, sum, MPFR_RNDN); 234929f144ccSMatthew G. Knepley mpfr_mul_d(h, h, 0.5, MPFR_RNDN); 235029f144ccSMatthew G. Knepley mpfr_mul_d(sum, sum, 0.5, MPFR_RNDN); 235129f144ccSMatthew G. Knepley do { 235229f144ccSMatthew G. Knepley mpfr_set_si(kh, k, MPFR_RNDN); 235329f144ccSMatthew G. Knepley mpfr_mul(kh, kh, h, MPFR_RNDN); 235429f144ccSMatthew G. Knepley /* Weight */ 235529f144ccSMatthew G. Knepley mpfr_set(wk, h, MPFR_RNDN); 235629f144ccSMatthew G. Knepley mpfr_sinh_cosh(msinh, mcosh, kh, MPFR_RNDN); 235729f144ccSMatthew G. Knepley mpfr_mul(msinh, msinh, pi2, MPFR_RNDN); 235829f144ccSMatthew G. Knepley mpfr_mul(mcosh, mcosh, pi2, MPFR_RNDN); 235929f144ccSMatthew G. Knepley mpfr_cosh(tmp, msinh, MPFR_RNDN); 236029f144ccSMatthew G. Knepley mpfr_sqr(tmp, tmp, MPFR_RNDN); 236129f144ccSMatthew G. Knepley mpfr_mul(wk, wk, mcosh, MPFR_RNDN); 236229f144ccSMatthew G. Knepley mpfr_div(wk, wk, tmp, MPFR_RNDN); 236329f144ccSMatthew G. Knepley /* Abscissa */ 236429f144ccSMatthew G. Knepley mpfr_set_d(yk, 1.0, MPFR_RNDZ); 236529f144ccSMatthew G. Knepley mpfr_cosh(tmp, msinh, MPFR_RNDN); 236629f144ccSMatthew G. Knepley mpfr_div(yk, yk, tmp, MPFR_RNDZ); 236729f144ccSMatthew G. Knepley mpfr_exp(tmp, msinh, MPFR_RNDN); 236829f144ccSMatthew G. Knepley mpfr_div(yk, yk, tmp, MPFR_RNDZ); 236929f144ccSMatthew G. Knepley /* Quadrature points */ 237029f144ccSMatthew G. Knepley mpfr_sub_d(lx, yk, 1.0, MPFR_RNDZ); 237129f144ccSMatthew G. Knepley mpfr_mul(lx, lx, alpha, MPFR_RNDU); 237229f144ccSMatthew G. Knepley mpfr_add(lx, lx, beta, MPFR_RNDU); 237329f144ccSMatthew G. Knepley mpfr_d_sub(rx, 1.0, yk, MPFR_RNDZ); 237429f144ccSMatthew G. Knepley mpfr_mul(rx, rx, alpha, MPFR_RNDD); 237529f144ccSMatthew G. Knepley mpfr_add(rx, rx, beta, MPFR_RNDD); 237629f144ccSMatthew G. Knepley /* Evaluation */ 23771fbc92bbSMatthew G. Knepley rtmp = mpfr_get_d(lx, MPFR_RNDU); 23781fbc92bbSMatthew G. Knepley func(&rtmp, ctx, &lval); 23791fbc92bbSMatthew G. Knepley rtmp = mpfr_get_d(rx, MPFR_RNDD); 23801fbc92bbSMatthew G. Knepley func(&rtmp, ctx, &rval); 238129f144ccSMatthew G. Knepley /* Update */ 238229f144ccSMatthew G. Knepley mpfr_mul(tmp, wk, alpha, MPFR_RNDN); 238329f144ccSMatthew G. Knepley mpfr_mul_d(tmp, tmp, lval, MPFR_RNDN); 238429f144ccSMatthew G. Knepley mpfr_add(sum, sum, tmp, MPFR_RNDN); 238529f144ccSMatthew G. Knepley mpfr_abs(tmp, tmp, MPFR_RNDN); 238629f144ccSMatthew G. Knepley mpfr_max(maxTerm, maxTerm, tmp, MPFR_RNDN); 238729f144ccSMatthew G. Knepley mpfr_set(curTerm, tmp, MPFR_RNDN); 238829f144ccSMatthew G. Knepley mpfr_mul(tmp, wk, alpha, MPFR_RNDN); 238929f144ccSMatthew G. Knepley mpfr_mul_d(tmp, tmp, rval, MPFR_RNDN); 239029f144ccSMatthew G. Knepley mpfr_add(sum, sum, tmp, MPFR_RNDN); 239129f144ccSMatthew G. Knepley mpfr_abs(tmp, tmp, MPFR_RNDN); 239229f144ccSMatthew G. Knepley mpfr_max(maxTerm, maxTerm, tmp, MPFR_RNDN); 239329f144ccSMatthew G. Knepley mpfr_max(curTerm, curTerm, tmp, MPFR_RNDN); 239429f144ccSMatthew G. Knepley ++k; 239529f144ccSMatthew G. Knepley /* Only need to evaluate every other point on refined levels */ 239629f144ccSMatthew G. Knepley if (l != 1) ++k; 239729f144ccSMatthew G. Knepley mpfr_log10(tmp, wk, MPFR_RNDN); 239829f144ccSMatthew G. Knepley mpfr_abs(tmp, tmp, MPFR_RNDN); 2399c9f744b5SMatthew G. Knepley } while (mpfr_get_d(tmp, MPFR_RNDN) < safetyFactor * digits); /* Only need to evaluate sum until weights are < 32 digits of precision */ 240029f144ccSMatthew G. Knepley mpfr_sub(tmp, sum, osum, MPFR_RNDN); 240129f144ccSMatthew G. Knepley mpfr_abs(tmp, tmp, MPFR_RNDN); 240229f144ccSMatthew G. Knepley mpfr_log10(tmp, tmp, MPFR_RNDN); 240329f144ccSMatthew G. Knepley d1 = mpfr_get_d(tmp, MPFR_RNDN); 240429f144ccSMatthew G. Knepley mpfr_sub(tmp, sum, psum, MPFR_RNDN); 240529f144ccSMatthew G. Knepley mpfr_abs(tmp, tmp, MPFR_RNDN); 240629f144ccSMatthew G. Knepley mpfr_log10(tmp, tmp, MPFR_RNDN); 240729f144ccSMatthew G. Knepley d2 = mpfr_get_d(tmp, MPFR_RNDN); 240829f144ccSMatthew G. Knepley mpfr_log10(tmp, maxTerm, MPFR_RNDN); 2409c9f744b5SMatthew G. Knepley d3 = mpfr_get_d(tmp, MPFR_RNDN) - digits; 241029f144ccSMatthew G. Knepley mpfr_log10(tmp, curTerm, MPFR_RNDN); 241129f144ccSMatthew G. Knepley d4 = mpfr_get_d(tmp, MPFR_RNDN); 241229f144ccSMatthew G. Knepley d = PetscAbsInt(PetscMin(0, PetscMax(PetscMax(PetscMax(PetscSqr(d1) / d2, 2 * d1), d3), d4))); 2413b0649871SThomas Klotz } while (d < digits && l < 8); 241429f144ccSMatthew G. Knepley *sol = mpfr_get_d(sum, MPFR_RNDN); 241529f144ccSMatthew G. Knepley /* Cleanup */ 241629f144ccSMatthew G. Knepley mpfr_clears(alpha, beta, h, sum, osum, psum, yk, wk, lx, rx, tmp, maxTerm, curTerm, pi2, kh, msinh, mcosh, NULL); 241729f144ccSMatthew G. Knepley PetscFunctionReturn(0); 241829f144ccSMatthew G. Knepley } 2419d525116cSMatthew G. Knepley #else 2420fbfcfee5SBarry Smith 2421*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDTTanhSinhIntegrateMPFR(void (*func)(const PetscReal[], void *, PetscReal *), PetscReal a, PetscReal b, PetscInt digits, void *ctx, PetscReal *sol) 2422*d71ae5a4SJacob Faibussowitsch { 2423d525116cSMatthew G. Knepley SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "This method will not work without MPFR. Reconfigure using --download-mpfr --download-gmp"); 2424d525116cSMatthew G. Knepley } 242529f144ccSMatthew G. Knepley #endif 242629f144ccSMatthew G. Knepley 24272df84da0SMatthew G. Knepley /*@ 24282df84da0SMatthew G. Knepley PetscDTTensorQuadratureCreate - create the tensor product quadrature from two lower-dimensional quadratures 24292df84da0SMatthew G. Knepley 24302df84da0SMatthew G. Knepley Not Collective 24312df84da0SMatthew G. Knepley 24322df84da0SMatthew G. Knepley Input Parameters: 24332df84da0SMatthew G. Knepley + q1 - The first quadrature 24342df84da0SMatthew G. Knepley - q2 - The second quadrature 24352df84da0SMatthew G. Knepley 24362df84da0SMatthew G. Knepley Output Parameter: 24372df84da0SMatthew G. Knepley . q - A PetscQuadrature object 24382df84da0SMatthew G. Knepley 24392df84da0SMatthew G. Knepley Level: intermediate 24402df84da0SMatthew G. Knepley 2441db781477SPatrick Sanan .seealso: `PetscDTGaussTensorQuadrature()` 24422df84da0SMatthew G. Knepley @*/ 2443*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDTTensorQuadratureCreate(PetscQuadrature q1, PetscQuadrature q2, PetscQuadrature *q) 2444*d71ae5a4SJacob Faibussowitsch { 24452df84da0SMatthew G. Knepley const PetscReal *x1, *w1, *x2, *w2; 24462df84da0SMatthew G. Knepley PetscReal *x, *w; 24472df84da0SMatthew G. Knepley PetscInt dim1, Nc1, Np1, order1, qa, d1; 24482df84da0SMatthew G. Knepley PetscInt dim2, Nc2, Np2, order2, qb, d2; 24492df84da0SMatthew G. Knepley PetscInt dim, Nc, Np, order, qc, d; 24502df84da0SMatthew G. Knepley 24512df84da0SMatthew G. Knepley PetscFunctionBegin; 24522df84da0SMatthew G. Knepley PetscValidHeaderSpecific(q1, PETSCQUADRATURE_CLASSID, 1); 24532df84da0SMatthew G. Knepley PetscValidHeaderSpecific(q2, PETSCQUADRATURE_CLASSID, 2); 24542df84da0SMatthew G. Knepley PetscValidPointer(q, 3); 24559566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetOrder(q1, &order1)); 24569566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetOrder(q2, &order2)); 24572df84da0SMatthew G. Knepley PetscCheck(order1 == order2, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Order1 %" PetscInt_FMT " != %" PetscInt_FMT " Order2", order1, order2); 24589566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(q1, &dim1, &Nc1, &Np1, &x1, &w1)); 24599566063dSJacob Faibussowitsch PetscCall(PetscQuadratureGetData(q2, &dim2, &Nc2, &Np2, &x2, &w2)); 24602df84da0SMatthew G. Knepley PetscCheck(Nc1 == Nc2, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "NumComp1 %" PetscInt_FMT " != %" PetscInt_FMT " NumComp2", Nc1, Nc2); 24612df84da0SMatthew G. Knepley 24622df84da0SMatthew G. Knepley dim = dim1 + dim2; 24632df84da0SMatthew G. Knepley Nc = Nc1; 24642df84da0SMatthew G. Knepley Np = Np1 * Np2; 24652df84da0SMatthew G. Knepley order = order1; 24669566063dSJacob Faibussowitsch PetscCall(PetscQuadratureCreate(PETSC_COMM_SELF, q)); 24679566063dSJacob Faibussowitsch PetscCall(PetscQuadratureSetOrder(*q, order)); 24689566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(Np * dim, &x)); 24699566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(Np, &w)); 24702df84da0SMatthew G. Knepley for (qa = 0, qc = 0; qa < Np1; ++qa) { 24712df84da0SMatthew G. Knepley for (qb = 0; qb < Np2; ++qb, ++qc) { 2472ad540459SPierre Jolivet for (d1 = 0, d = 0; d1 < dim1; ++d1, ++d) x[qc * dim + d] = x1[qa * dim1 + d1]; 2473ad540459SPierre Jolivet for (d2 = 0; d2 < dim2; ++d2, ++d) x[qc * dim + d] = x2[qb * dim2 + d2]; 24742df84da0SMatthew G. Knepley w[qc] = w1[qa] * w2[qb]; 24752df84da0SMatthew G. Knepley } 24762df84da0SMatthew G. Knepley } 24779566063dSJacob Faibussowitsch PetscCall(PetscQuadratureSetData(*q, dim, Nc, Np, x, w)); 24782df84da0SMatthew G. Knepley PetscFunctionReturn(0); 24792df84da0SMatthew G. Knepley } 24802df84da0SMatthew G. Knepley 2481194825f6SJed Brown /* Overwrites A. Can only handle full-rank problems with m>=n 2482194825f6SJed Brown * A in column-major format 2483194825f6SJed Brown * Ainv in row-major format 2484194825f6SJed Brown * tau has length m 2485194825f6SJed Brown * worksize must be >= max(1,n) 2486194825f6SJed Brown */ 2487*d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDTPseudoInverseQR(PetscInt m, PetscInt mstride, PetscInt n, PetscReal *A_in, PetscReal *Ainv_out, PetscScalar *tau, PetscInt worksize, PetscScalar *work) 2488*d71ae5a4SJacob Faibussowitsch { 2489194825f6SJed Brown PetscBLASInt M, N, K, lda, ldb, ldwork, info; 2490194825f6SJed Brown PetscScalar *A, *Ainv, *R, *Q, Alpha; 2491194825f6SJed Brown 2492194825f6SJed Brown PetscFunctionBegin; 2493194825f6SJed Brown #if defined(PETSC_USE_COMPLEX) 2494194825f6SJed Brown { 2495194825f6SJed Brown PetscInt i, j; 24969566063dSJacob Faibussowitsch PetscCall(PetscMalloc2(m * n, &A, m * n, &Ainv)); 2497194825f6SJed Brown for (j = 0; j < n; j++) { 2498194825f6SJed Brown for (i = 0; i < m; i++) A[i + m * j] = A_in[i + mstride * j]; 2499194825f6SJed Brown } 2500194825f6SJed Brown mstride = m; 2501194825f6SJed Brown } 2502194825f6SJed Brown #else 2503194825f6SJed Brown A = A_in; 2504194825f6SJed Brown Ainv = Ainv_out; 2505194825f6SJed Brown #endif 2506194825f6SJed Brown 25079566063dSJacob Faibussowitsch PetscCall(PetscBLASIntCast(m, &M)); 25089566063dSJacob Faibussowitsch PetscCall(PetscBLASIntCast(n, &N)); 25099566063dSJacob Faibussowitsch PetscCall(PetscBLASIntCast(mstride, &lda)); 25109566063dSJacob Faibussowitsch PetscCall(PetscBLASIntCast(worksize, &ldwork)); 25119566063dSJacob Faibussowitsch PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF)); 2512792fecdfSBarry Smith PetscCallBLAS("LAPACKgeqrf", LAPACKgeqrf_(&M, &N, A, &lda, tau, work, &ldwork, &info)); 25139566063dSJacob Faibussowitsch PetscCall(PetscFPTrapPop()); 251428b400f6SJacob Faibussowitsch PetscCheck(!info, PETSC_COMM_SELF, PETSC_ERR_LIB, "xGEQRF error"); 2515194825f6SJed Brown R = A; /* Upper triangular part of A now contains R, the rest contains the elementary reflectors */ 2516194825f6SJed Brown 2517194825f6SJed Brown /* Extract an explicit representation of Q */ 2518194825f6SJed Brown Q = Ainv; 25199566063dSJacob Faibussowitsch PetscCall(PetscArraycpy(Q, A, mstride * n)); 2520194825f6SJed Brown K = N; /* full rank */ 2521792fecdfSBarry Smith PetscCallBLAS("LAPACKorgqr", LAPACKorgqr_(&M, &N, &K, Q, &lda, tau, work, &ldwork, &info)); 252228b400f6SJacob Faibussowitsch PetscCheck(!info, PETSC_COMM_SELF, PETSC_ERR_LIB, "xORGQR/xUNGQR error"); 2523194825f6SJed Brown 2524194825f6SJed Brown /* Compute A^{-T} = (R^{-1} Q^T)^T = Q R^{-T} */ 2525194825f6SJed Brown Alpha = 1.0; 2526194825f6SJed Brown ldb = lda; 2527792fecdfSBarry Smith PetscCallBLAS("BLAStrsm", BLAStrsm_("Right", "Upper", "ConjugateTranspose", "NotUnitTriangular", &M, &N, &Alpha, R, &lda, Q, &ldb)); 2528194825f6SJed Brown /* Ainv is Q, overwritten with inverse */ 2529194825f6SJed Brown 2530194825f6SJed Brown #if defined(PETSC_USE_COMPLEX) 2531194825f6SJed Brown { 2532194825f6SJed Brown PetscInt i; 2533194825f6SJed Brown for (i = 0; i < m * n; i++) Ainv_out[i] = PetscRealPart(Ainv[i]); 25349566063dSJacob Faibussowitsch PetscCall(PetscFree2(A, Ainv)); 2535194825f6SJed Brown } 2536194825f6SJed Brown #endif 2537194825f6SJed Brown PetscFunctionReturn(0); 2538194825f6SJed Brown } 2539194825f6SJed Brown 2540194825f6SJed Brown /* Computes integral of L_p' over intervals {(x0,x1),(x1,x2),...} */ 2541*d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscDTLegendreIntegrate(PetscInt ninterval, const PetscReal *x, PetscInt ndegree, const PetscInt *degrees, PetscBool Transpose, PetscReal *B) 2542*d71ae5a4SJacob Faibussowitsch { 2543194825f6SJed Brown PetscReal *Bv; 2544194825f6SJed Brown PetscInt i, j; 2545194825f6SJed Brown 2546194825f6SJed Brown PetscFunctionBegin; 25479566063dSJacob Faibussowitsch PetscCall(PetscMalloc1((ninterval + 1) * ndegree, &Bv)); 2548194825f6SJed Brown /* Point evaluation of L_p on all the source vertices */ 25499566063dSJacob Faibussowitsch PetscCall(PetscDTLegendreEval(ninterval + 1, x, ndegree, degrees, Bv, NULL, NULL)); 2550194825f6SJed Brown /* Integral over each interval: \int_a^b L_p' = L_p(b)-L_p(a) */ 2551194825f6SJed Brown for (i = 0; i < ninterval; i++) { 2552194825f6SJed Brown for (j = 0; j < ndegree; j++) { 2553194825f6SJed Brown if (Transpose) B[i + ninterval * j] = Bv[(i + 1) * ndegree + j] - Bv[i * ndegree + j]; 2554194825f6SJed Brown else B[i * ndegree + j] = Bv[(i + 1) * ndegree + j] - Bv[i * ndegree + j]; 2555194825f6SJed Brown } 2556194825f6SJed Brown } 25579566063dSJacob Faibussowitsch PetscCall(PetscFree(Bv)); 2558194825f6SJed Brown PetscFunctionReturn(0); 2559194825f6SJed Brown } 2560194825f6SJed Brown 2561194825f6SJed Brown /*@ 2562194825f6SJed Brown PetscDTReconstructPoly - create matrix representing polynomial reconstruction using cell intervals and evaluation at target intervals 2563194825f6SJed Brown 2564194825f6SJed Brown Not Collective 2565194825f6SJed Brown 25664165533cSJose E. Roman Input Parameters: 2567194825f6SJed Brown + degree - degree of reconstruction polynomial 2568194825f6SJed Brown . nsource - number of source intervals 2569194825f6SJed Brown . sourcex - sorted coordinates of source cell boundaries (length nsource+1) 2570194825f6SJed Brown . ntarget - number of target intervals 2571194825f6SJed Brown - targetx - sorted coordinates of target cell boundaries (length ntarget+1) 2572194825f6SJed Brown 25734165533cSJose E. Roman Output Parameter: 2574194825f6SJed Brown . R - reconstruction matrix, utarget = sum_s R[t*nsource+s] * usource[s] 2575194825f6SJed Brown 2576194825f6SJed Brown Level: advanced 2577194825f6SJed Brown 2578db781477SPatrick Sanan .seealso: `PetscDTLegendreEval()` 2579194825f6SJed Brown @*/ 2580*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDTReconstructPoly(PetscInt degree, PetscInt nsource, const PetscReal *sourcex, PetscInt ntarget, const PetscReal *targetx, PetscReal *R) 2581*d71ae5a4SJacob Faibussowitsch { 2582194825f6SJed Brown PetscInt i, j, k, *bdegrees, worksize; 2583194825f6SJed Brown PetscReal xmin, xmax, center, hscale, *sourcey, *targety, *Bsource, *Bsinv, *Btarget; 2584194825f6SJed Brown PetscScalar *tau, *work; 2585194825f6SJed Brown 2586194825f6SJed Brown PetscFunctionBegin; 2587194825f6SJed Brown PetscValidRealPointer(sourcex, 3); 2588194825f6SJed Brown PetscValidRealPointer(targetx, 5); 2589194825f6SJed Brown PetscValidRealPointer(R, 6); 259063a3b9bcSJacob 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); 259176bd3646SJed Brown if (PetscDefined(USE_DEBUG)) { 2592ad540459SPierre Jolivet 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]); 2593ad540459SPierre Jolivet 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]); 259476bd3646SJed Brown } 2595194825f6SJed Brown xmin = PetscMin(sourcex[0], targetx[0]); 2596194825f6SJed Brown xmax = PetscMax(sourcex[nsource], targetx[ntarget]); 2597194825f6SJed Brown center = (xmin + xmax) / 2; 2598194825f6SJed Brown hscale = (xmax - xmin) / 2; 2599194825f6SJed Brown worksize = nsource; 26009566063dSJacob Faibussowitsch PetscCall(PetscMalloc4(degree + 1, &bdegrees, nsource + 1, &sourcey, nsource * (degree + 1), &Bsource, worksize, &work)); 26019566063dSJacob Faibussowitsch PetscCall(PetscMalloc4(nsource, &tau, nsource * (degree + 1), &Bsinv, ntarget + 1, &targety, ntarget * (degree + 1), &Btarget)); 2602194825f6SJed Brown for (i = 0; i <= nsource; i++) sourcey[i] = (sourcex[i] - center) / hscale; 2603194825f6SJed Brown for (i = 0; i <= degree; i++) bdegrees[i] = i + 1; 26049566063dSJacob Faibussowitsch PetscCall(PetscDTLegendreIntegrate(nsource, sourcey, degree + 1, bdegrees, PETSC_TRUE, Bsource)); 26059566063dSJacob Faibussowitsch PetscCall(PetscDTPseudoInverseQR(nsource, nsource, degree + 1, Bsource, Bsinv, tau, nsource, work)); 2606194825f6SJed Brown for (i = 0; i <= ntarget; i++) targety[i] = (targetx[i] - center) / hscale; 26079566063dSJacob Faibussowitsch PetscCall(PetscDTLegendreIntegrate(ntarget, targety, degree + 1, bdegrees, PETSC_FALSE, Btarget)); 2608194825f6SJed Brown for (i = 0; i < ntarget; i++) { 2609194825f6SJed Brown PetscReal rowsum = 0; 2610194825f6SJed Brown for (j = 0; j < nsource; j++) { 2611194825f6SJed Brown PetscReal sum = 0; 2612ad540459SPierre Jolivet for (k = 0; k < degree + 1; k++) sum += Btarget[i * (degree + 1) + k] * Bsinv[k * nsource + j]; 2613194825f6SJed Brown R[i * nsource + j] = sum; 2614194825f6SJed Brown rowsum += sum; 2615194825f6SJed Brown } 2616194825f6SJed Brown for (j = 0; j < nsource; j++) R[i * nsource + j] /= rowsum; /* normalize each row */ 2617194825f6SJed Brown } 26189566063dSJacob Faibussowitsch PetscCall(PetscFree4(bdegrees, sourcey, Bsource, work)); 26199566063dSJacob Faibussowitsch PetscCall(PetscFree4(tau, Bsinv, targety, Btarget)); 2620194825f6SJed Brown PetscFunctionReturn(0); 2621194825f6SJed Brown } 2622916e780bShannah_mairs 2623916e780bShannah_mairs /*@C 2624916e780bShannah_mairs PetscGaussLobattoLegendreIntegrate - Compute the L2 integral of a function on the GLL points 2625916e780bShannah_mairs 2626916e780bShannah_mairs Not Collective 2627916e780bShannah_mairs 2628d8d19677SJose E. Roman Input Parameters: 2629916e780bShannah_mairs + n - the number of GLL nodes 2630916e780bShannah_mairs . nodes - the GLL nodes 2631916e780bShannah_mairs . weights - the GLL weights 2632f0fc11ceSJed Brown - f - the function values at the nodes 2633916e780bShannah_mairs 2634916e780bShannah_mairs Output Parameter: 2635916e780bShannah_mairs . in - the value of the integral 2636916e780bShannah_mairs 2637916e780bShannah_mairs Level: beginner 2638916e780bShannah_mairs 2639db781477SPatrick Sanan .seealso: `PetscDTGaussLobattoLegendreQuadrature()` 2640916e780bShannah_mairs 2641916e780bShannah_mairs @*/ 2642*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscGaussLobattoLegendreIntegrate(PetscInt n, PetscReal *nodes, PetscReal *weights, const PetscReal *f, PetscReal *in) 2643*d71ae5a4SJacob Faibussowitsch { 2644916e780bShannah_mairs PetscInt i; 2645916e780bShannah_mairs 2646916e780bShannah_mairs PetscFunctionBegin; 2647916e780bShannah_mairs *in = 0.; 2648ad540459SPierre Jolivet for (i = 0; i < n; i++) *in += f[i] * f[i] * weights[i]; 2649916e780bShannah_mairs PetscFunctionReturn(0); 2650916e780bShannah_mairs } 2651916e780bShannah_mairs 2652916e780bShannah_mairs /*@C 2653916e780bShannah_mairs PetscGaussLobattoLegendreElementLaplacianCreate - computes the Laplacian for a single 1d GLL element 2654916e780bShannah_mairs 2655916e780bShannah_mairs Not Collective 2656916e780bShannah_mairs 2657d8d19677SJose E. Roman Input Parameters: 2658916e780bShannah_mairs + n - the number of GLL nodes 2659916e780bShannah_mairs . nodes - the GLL nodes 2660f0fc11ceSJed Brown - weights - the GLL weights 2661916e780bShannah_mairs 2662916e780bShannah_mairs Output Parameter: 2663916e780bShannah_mairs . A - the stiffness element 2664916e780bShannah_mairs 2665916e780bShannah_mairs Level: beginner 2666916e780bShannah_mairs 2667916e780bShannah_mairs Notes: 2668916e780bShannah_mairs Destroy this with PetscGaussLobattoLegendreElementLaplacianDestroy() 2669916e780bShannah_mairs 2670916e780bShannah_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) 2671916e780bShannah_mairs 2672db781477SPatrick Sanan .seealso: `PetscDTGaussLobattoLegendreQuadrature()`, `PetscGaussLobattoLegendreElementLaplacianDestroy()` 2673916e780bShannah_mairs 2674916e780bShannah_mairs @*/ 2675*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscGaussLobattoLegendreElementLaplacianCreate(PetscInt n, PetscReal *nodes, PetscReal *weights, PetscReal ***AA) 2676*d71ae5a4SJacob Faibussowitsch { 2677916e780bShannah_mairs PetscReal **A; 2678916e780bShannah_mairs const PetscReal *gllnodes = nodes; 2679916e780bShannah_mairs const PetscInt p = n - 1; 2680916e780bShannah_mairs PetscReal z0, z1, z2 = -1, x, Lpj, Lpr; 2681916e780bShannah_mairs PetscInt i, j, nn, r; 2682916e780bShannah_mairs 2683916e780bShannah_mairs PetscFunctionBegin; 26849566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(n, &A)); 26859566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(n * n, &A[0])); 2686916e780bShannah_mairs for (i = 1; i < n; i++) A[i] = A[i - 1] + n; 2687916e780bShannah_mairs 2688916e780bShannah_mairs for (j = 1; j < p; j++) { 2689916e780bShannah_mairs x = gllnodes[j]; 2690916e780bShannah_mairs z0 = 1.; 2691916e780bShannah_mairs z1 = x; 2692916e780bShannah_mairs for (nn = 1; nn < p; nn++) { 2693916e780bShannah_mairs z2 = x * z1 * (2. * ((PetscReal)nn) + 1.) / (((PetscReal)nn) + 1.) - z0 * (((PetscReal)nn) / (((PetscReal)nn) + 1.)); 2694916e780bShannah_mairs z0 = z1; 2695916e780bShannah_mairs z1 = z2; 2696916e780bShannah_mairs } 2697916e780bShannah_mairs Lpj = z2; 2698916e780bShannah_mairs for (r = 1; r < p; r++) { 2699916e780bShannah_mairs if (r == j) { 2700916e780bShannah_mairs A[j][j] = 2. / (3. * (1. - gllnodes[j] * gllnodes[j]) * Lpj * Lpj); 2701916e780bShannah_mairs } else { 2702916e780bShannah_mairs x = gllnodes[r]; 2703916e780bShannah_mairs z0 = 1.; 2704916e780bShannah_mairs z1 = x; 2705916e780bShannah_mairs for (nn = 1; nn < p; nn++) { 2706916e780bShannah_mairs z2 = x * z1 * (2. * ((PetscReal)nn) + 1.) / (((PetscReal)nn) + 1.) - z0 * (((PetscReal)nn) / (((PetscReal)nn) + 1.)); 2707916e780bShannah_mairs z0 = z1; 2708916e780bShannah_mairs z1 = z2; 2709916e780bShannah_mairs } 2710916e780bShannah_mairs Lpr = z2; 2711916e780bShannah_mairs A[r][j] = 4. / (((PetscReal)p) * (((PetscReal)p) + 1.) * Lpj * Lpr * (gllnodes[j] - gllnodes[r]) * (gllnodes[j] - gllnodes[r])); 2712916e780bShannah_mairs } 2713916e780bShannah_mairs } 2714916e780bShannah_mairs } 2715916e780bShannah_mairs for (j = 1; j < p + 1; j++) { 2716916e780bShannah_mairs x = gllnodes[j]; 2717916e780bShannah_mairs z0 = 1.; 2718916e780bShannah_mairs z1 = x; 2719916e780bShannah_mairs for (nn = 1; nn < p; nn++) { 2720916e780bShannah_mairs z2 = x * z1 * (2. * ((PetscReal)nn) + 1.) / (((PetscReal)nn) + 1.) - z0 * (((PetscReal)nn) / (((PetscReal)nn) + 1.)); 2721916e780bShannah_mairs z0 = z1; 2722916e780bShannah_mairs z1 = z2; 2723916e780bShannah_mairs } 2724916e780bShannah_mairs Lpj = z2; 2725916e780bShannah_mairs A[j][0] = 4. * PetscPowRealInt(-1., p) / (((PetscReal)p) * (((PetscReal)p) + 1.) * Lpj * (1. + gllnodes[j]) * (1. + gllnodes[j])); 2726916e780bShannah_mairs A[0][j] = A[j][0]; 2727916e780bShannah_mairs } 2728916e780bShannah_mairs for (j = 0; j < p; j++) { 2729916e780bShannah_mairs x = gllnodes[j]; 2730916e780bShannah_mairs z0 = 1.; 2731916e780bShannah_mairs z1 = x; 2732916e780bShannah_mairs for (nn = 1; nn < p; nn++) { 2733916e780bShannah_mairs z2 = x * z1 * (2. * ((PetscReal)nn) + 1.) / (((PetscReal)nn) + 1.) - z0 * (((PetscReal)nn) / (((PetscReal)nn) + 1.)); 2734916e780bShannah_mairs z0 = z1; 2735916e780bShannah_mairs z1 = z2; 2736916e780bShannah_mairs } 2737916e780bShannah_mairs Lpj = z2; 2738916e780bShannah_mairs 2739916e780bShannah_mairs A[p][j] = 4. / (((PetscReal)p) * (((PetscReal)p) + 1.) * Lpj * (1. - gllnodes[j]) * (1. - gllnodes[j])); 2740916e780bShannah_mairs A[j][p] = A[p][j]; 2741916e780bShannah_mairs } 2742916e780bShannah_mairs A[0][0] = 0.5 + (((PetscReal)p) * (((PetscReal)p) + 1.) - 2.) / 6.; 2743916e780bShannah_mairs A[p][p] = A[0][0]; 2744916e780bShannah_mairs *AA = A; 2745916e780bShannah_mairs PetscFunctionReturn(0); 2746916e780bShannah_mairs } 2747916e780bShannah_mairs 2748916e780bShannah_mairs /*@C 2749916e780bShannah_mairs PetscGaussLobattoLegendreElementLaplacianDestroy - frees the Laplacian for a single 1d GLL element 2750916e780bShannah_mairs 2751916e780bShannah_mairs Not Collective 2752916e780bShannah_mairs 2753d8d19677SJose E. Roman Input Parameters: 2754916e780bShannah_mairs + n - the number of GLL nodes 2755916e780bShannah_mairs . nodes - the GLL nodes 2756916e780bShannah_mairs . weights - the GLL weightss 2757916e780bShannah_mairs - A - the stiffness element 2758916e780bShannah_mairs 2759916e780bShannah_mairs Level: beginner 2760916e780bShannah_mairs 2761db781477SPatrick Sanan .seealso: `PetscDTGaussLobattoLegendreQuadrature()`, `PetscGaussLobattoLegendreElementLaplacianCreate()` 2762916e780bShannah_mairs 2763916e780bShannah_mairs @*/ 2764*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscGaussLobattoLegendreElementLaplacianDestroy(PetscInt n, PetscReal *nodes, PetscReal *weights, PetscReal ***AA) 2765*d71ae5a4SJacob Faibussowitsch { 2766916e780bShannah_mairs PetscFunctionBegin; 27679566063dSJacob Faibussowitsch PetscCall(PetscFree((*AA)[0])); 27689566063dSJacob Faibussowitsch PetscCall(PetscFree(*AA)); 2769916e780bShannah_mairs *AA = NULL; 2770916e780bShannah_mairs PetscFunctionReturn(0); 2771916e780bShannah_mairs } 2772916e780bShannah_mairs 2773916e780bShannah_mairs /*@C 2774916e780bShannah_mairs PetscGaussLobattoLegendreElementGradientCreate - computes the gradient for a single 1d GLL element 2775916e780bShannah_mairs 2776916e780bShannah_mairs Not Collective 2777916e780bShannah_mairs 2778916e780bShannah_mairs Input Parameter: 2779916e780bShannah_mairs + n - the number of GLL nodes 2780916e780bShannah_mairs . nodes - the GLL nodes 2781916e780bShannah_mairs . weights - the GLL weights 2782916e780bShannah_mairs 2783d8d19677SJose E. Roman Output Parameters: 2784916e780bShannah_mairs . AA - the stiffness element 2785916e780bShannah_mairs - AAT - the transpose of AA (pass in NULL if you do not need this array) 2786916e780bShannah_mairs 2787916e780bShannah_mairs Level: beginner 2788916e780bShannah_mairs 2789916e780bShannah_mairs Notes: 2790916e780bShannah_mairs Destroy this with PetscGaussLobattoLegendreElementGradientDestroy() 2791916e780bShannah_mairs 2792916e780bShannah_mairs You can access entries in these arrays with AA[i][j] but in memory it is stored in contiguous memory, row oriented 2793916e780bShannah_mairs 2794db781477SPatrick Sanan .seealso: `PetscDTGaussLobattoLegendreQuadrature()`, `PetscGaussLobattoLegendreElementLaplacianDestroy()` 2795916e780bShannah_mairs 2796916e780bShannah_mairs @*/ 2797*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscGaussLobattoLegendreElementGradientCreate(PetscInt n, PetscReal *nodes, PetscReal *weights, PetscReal ***AA, PetscReal ***AAT) 2798*d71ae5a4SJacob Faibussowitsch { 2799916e780bShannah_mairs PetscReal **A, **AT = NULL; 2800916e780bShannah_mairs const PetscReal *gllnodes = nodes; 2801916e780bShannah_mairs const PetscInt p = n - 1; 2802e6a796c3SToby Isaac PetscReal Li, Lj, d0; 2803916e780bShannah_mairs PetscInt i, j; 2804916e780bShannah_mairs 2805916e780bShannah_mairs PetscFunctionBegin; 28069566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(n, &A)); 28079566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(n * n, &A[0])); 2808916e780bShannah_mairs for (i = 1; i < n; i++) A[i] = A[i - 1] + n; 2809916e780bShannah_mairs 2810916e780bShannah_mairs if (AAT) { 28119566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(n, &AT)); 28129566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(n * n, &AT[0])); 2813916e780bShannah_mairs for (i = 1; i < n; i++) AT[i] = AT[i - 1] + n; 2814916e780bShannah_mairs } 2815916e780bShannah_mairs 2816ad540459SPierre Jolivet if (n == 1) A[0][0] = 0.; 2817916e780bShannah_mairs d0 = (PetscReal)p * ((PetscReal)p + 1.) / 4.; 2818916e780bShannah_mairs for (i = 0; i < n; i++) { 2819916e780bShannah_mairs for (j = 0; j < n; j++) { 2820916e780bShannah_mairs A[i][j] = 0.; 28219566063dSJacob Faibussowitsch PetscCall(PetscDTComputeJacobi(0., 0., p, gllnodes[i], &Li)); 28229566063dSJacob Faibussowitsch PetscCall(PetscDTComputeJacobi(0., 0., p, gllnodes[j], &Lj)); 2823916e780bShannah_mairs if (i != j) A[i][j] = Li / (Lj * (gllnodes[i] - gllnodes[j])); 2824916e780bShannah_mairs if ((j == i) && (i == 0)) A[i][j] = -d0; 2825916e780bShannah_mairs if (j == i && i == p) A[i][j] = d0; 2826916e780bShannah_mairs if (AT) AT[j][i] = A[i][j]; 2827916e780bShannah_mairs } 2828916e780bShannah_mairs } 2829916e780bShannah_mairs if (AAT) *AAT = AT; 2830916e780bShannah_mairs *AA = A; 2831916e780bShannah_mairs PetscFunctionReturn(0); 2832916e780bShannah_mairs } 2833916e780bShannah_mairs 2834916e780bShannah_mairs /*@C 2835916e780bShannah_mairs PetscGaussLobattoLegendreElementGradientDestroy - frees the gradient for a single 1d GLL element obtained with PetscGaussLobattoLegendreElementGradientCreate() 2836916e780bShannah_mairs 2837916e780bShannah_mairs Not Collective 2838916e780bShannah_mairs 2839d8d19677SJose E. Roman Input Parameters: 2840916e780bShannah_mairs + n - the number of GLL nodes 2841916e780bShannah_mairs . nodes - the GLL nodes 2842916e780bShannah_mairs . weights - the GLL weights 2843916e780bShannah_mairs . AA - the stiffness element 2844916e780bShannah_mairs - AAT - the transpose of the element 2845916e780bShannah_mairs 2846916e780bShannah_mairs Level: beginner 2847916e780bShannah_mairs 2848db781477SPatrick Sanan .seealso: `PetscDTGaussLobattoLegendreQuadrature()`, `PetscGaussLobattoLegendreElementLaplacianCreate()`, `PetscGaussLobattoLegendreElementAdvectionCreate()` 2849916e780bShannah_mairs 2850916e780bShannah_mairs @*/ 2851*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscGaussLobattoLegendreElementGradientDestroy(PetscInt n, PetscReal *nodes, PetscReal *weights, PetscReal ***AA, PetscReal ***AAT) 2852*d71ae5a4SJacob Faibussowitsch { 2853916e780bShannah_mairs PetscFunctionBegin; 28549566063dSJacob Faibussowitsch PetscCall(PetscFree((*AA)[0])); 28559566063dSJacob Faibussowitsch PetscCall(PetscFree(*AA)); 2856916e780bShannah_mairs *AA = NULL; 2857916e780bShannah_mairs if (*AAT) { 28589566063dSJacob Faibussowitsch PetscCall(PetscFree((*AAT)[0])); 28599566063dSJacob Faibussowitsch PetscCall(PetscFree(*AAT)); 2860916e780bShannah_mairs *AAT = NULL; 2861916e780bShannah_mairs } 2862916e780bShannah_mairs PetscFunctionReturn(0); 2863916e780bShannah_mairs } 2864916e780bShannah_mairs 2865916e780bShannah_mairs /*@C 2866916e780bShannah_mairs PetscGaussLobattoLegendreElementAdvectionCreate - computes the advection operator for a single 1d GLL element 2867916e780bShannah_mairs 2868916e780bShannah_mairs Not Collective 2869916e780bShannah_mairs 2870d8d19677SJose E. Roman Input Parameters: 2871916e780bShannah_mairs + n - the number of GLL nodes 2872916e780bShannah_mairs . nodes - the GLL nodes 2873f0fc11ceSJed Brown - weights - the GLL weightss 2874916e780bShannah_mairs 2875916e780bShannah_mairs Output Parameter: 2876916e780bShannah_mairs . AA - the stiffness element 2877916e780bShannah_mairs 2878916e780bShannah_mairs Level: beginner 2879916e780bShannah_mairs 2880916e780bShannah_mairs Notes: 2881916e780bShannah_mairs Destroy this with PetscGaussLobattoLegendreElementAdvectionDestroy() 2882916e780bShannah_mairs 2883916e780bShannah_mairs This is the same as the Gradient operator multiplied by the diagonal mass matrix 2884916e780bShannah_mairs 2885916e780bShannah_mairs You can access entries in this array with AA[i][j] but in memory it is stored in contiguous memory, row oriented 2886916e780bShannah_mairs 2887db781477SPatrick Sanan .seealso: `PetscDTGaussLobattoLegendreQuadrature()`, `PetscGaussLobattoLegendreElementLaplacianCreate()`, `PetscGaussLobattoLegendreElementAdvectionDestroy()` 2888916e780bShannah_mairs 2889916e780bShannah_mairs @*/ 2890*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscGaussLobattoLegendreElementAdvectionCreate(PetscInt n, PetscReal *nodes, PetscReal *weights, PetscReal ***AA) 2891*d71ae5a4SJacob Faibussowitsch { 2892916e780bShannah_mairs PetscReal **D; 2893916e780bShannah_mairs const PetscReal *gllweights = weights; 2894916e780bShannah_mairs const PetscInt glln = n; 2895916e780bShannah_mairs PetscInt i, j; 2896916e780bShannah_mairs 2897916e780bShannah_mairs PetscFunctionBegin; 28989566063dSJacob Faibussowitsch PetscCall(PetscGaussLobattoLegendreElementGradientCreate(n, nodes, weights, &D, NULL)); 2899916e780bShannah_mairs for (i = 0; i < glln; i++) { 2900ad540459SPierre Jolivet for (j = 0; j < glln; j++) D[i][j] = gllweights[i] * D[i][j]; 2901916e780bShannah_mairs } 2902916e780bShannah_mairs *AA = D; 2903916e780bShannah_mairs PetscFunctionReturn(0); 2904916e780bShannah_mairs } 2905916e780bShannah_mairs 2906916e780bShannah_mairs /*@C 2907916e780bShannah_mairs PetscGaussLobattoLegendreElementAdvectionDestroy - frees the advection stiffness for a single 1d GLL element 2908916e780bShannah_mairs 2909916e780bShannah_mairs Not Collective 2910916e780bShannah_mairs 2911d8d19677SJose E. Roman Input Parameters: 2912916e780bShannah_mairs + n - the number of GLL nodes 2913916e780bShannah_mairs . nodes - the GLL nodes 2914916e780bShannah_mairs . weights - the GLL weights 2915916e780bShannah_mairs - A - advection 2916916e780bShannah_mairs 2917916e780bShannah_mairs Level: beginner 2918916e780bShannah_mairs 2919db781477SPatrick Sanan .seealso: `PetscDTGaussLobattoLegendreQuadrature()`, `PetscGaussLobattoLegendreElementAdvectionCreate()` 2920916e780bShannah_mairs 2921916e780bShannah_mairs @*/ 2922*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscGaussLobattoLegendreElementAdvectionDestroy(PetscInt n, PetscReal *nodes, PetscReal *weights, PetscReal ***AA) 2923*d71ae5a4SJacob Faibussowitsch { 2924916e780bShannah_mairs PetscFunctionBegin; 29259566063dSJacob Faibussowitsch PetscCall(PetscFree((*AA)[0])); 29269566063dSJacob Faibussowitsch PetscCall(PetscFree(*AA)); 2927916e780bShannah_mairs *AA = NULL; 2928916e780bShannah_mairs PetscFunctionReturn(0); 2929916e780bShannah_mairs } 2930916e780bShannah_mairs 2931*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscGaussLobattoLegendreElementMassCreate(PetscInt n, PetscReal *nodes, PetscReal *weights, PetscReal ***AA) 2932*d71ae5a4SJacob Faibussowitsch { 2933916e780bShannah_mairs PetscReal **A; 2934916e780bShannah_mairs const PetscReal *gllweights = weights; 2935916e780bShannah_mairs const PetscInt glln = n; 2936916e780bShannah_mairs PetscInt i, j; 2937916e780bShannah_mairs 2938916e780bShannah_mairs PetscFunctionBegin; 29399566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(glln, &A)); 29409566063dSJacob Faibussowitsch PetscCall(PetscMalloc1(glln * glln, &A[0])); 2941916e780bShannah_mairs for (i = 1; i < glln; i++) A[i] = A[i - 1] + glln; 2942ad540459SPierre Jolivet if (glln == 1) A[0][0] = 0.; 2943916e780bShannah_mairs for (i = 0; i < glln; i++) { 2944916e780bShannah_mairs for (j = 0; j < glln; j++) { 2945916e780bShannah_mairs A[i][j] = 0.; 2946916e780bShannah_mairs if (j == i) A[i][j] = gllweights[i]; 2947916e780bShannah_mairs } 2948916e780bShannah_mairs } 2949916e780bShannah_mairs *AA = A; 2950916e780bShannah_mairs PetscFunctionReturn(0); 2951916e780bShannah_mairs } 2952916e780bShannah_mairs 2953*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscGaussLobattoLegendreElementMassDestroy(PetscInt n, PetscReal *nodes, PetscReal *weights, PetscReal ***AA) 2954*d71ae5a4SJacob Faibussowitsch { 2955916e780bShannah_mairs PetscFunctionBegin; 29569566063dSJacob Faibussowitsch PetscCall(PetscFree((*AA)[0])); 29579566063dSJacob Faibussowitsch PetscCall(PetscFree(*AA)); 2958916e780bShannah_mairs *AA = NULL; 2959916e780bShannah_mairs PetscFunctionReturn(0); 2960916e780bShannah_mairs } 2961d4afb720SToby Isaac 2962d4afb720SToby Isaac /*@ 2963d4afb720SToby Isaac PetscDTIndexToBary - convert an index into a barycentric coordinate. 2964d4afb720SToby Isaac 2965d4afb720SToby Isaac Input Parameters: 2966d4afb720SToby 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) 2967d4afb720SToby Isaac . sum - the value that the sum of the barycentric coordinates (which will be non-negative integers) should sum to 2968d4afb720SToby Isaac - index - the index to convert: should be >= 0 and < Binomial(len - 1 + sum, sum) 2969d4afb720SToby Isaac 2970d4afb720SToby Isaac Output Parameter: 2971d4afb720SToby Isaac . coord - will be filled with the barycentric coordinate 2972d4afb720SToby Isaac 2973d4afb720SToby Isaac Level: beginner 2974d4afb720SToby Isaac 2975d4afb720SToby Isaac Note: the indices map to barycentric coordinates in lexicographic order, where the first index is the 2976d4afb720SToby Isaac least significant and the last index is the most significant. 2977d4afb720SToby Isaac 2978db781477SPatrick Sanan .seealso: `PetscDTBaryToIndex()` 2979d4afb720SToby Isaac @*/ 2980*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDTIndexToBary(PetscInt len, PetscInt sum, PetscInt index, PetscInt coord[]) 2981*d71ae5a4SJacob Faibussowitsch { 2982d4afb720SToby Isaac PetscInt c, d, s, total, subtotal, nexttotal; 2983d4afb720SToby Isaac 2984d4afb720SToby Isaac PetscFunctionBeginHot; 298508401ef6SPierre Jolivet PetscCheck(len >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "length must be non-negative"); 298608401ef6SPierre Jolivet PetscCheck(index >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "index must be non-negative"); 2987d4afb720SToby Isaac if (!len) { 2988d4afb720SToby Isaac if (!sum && !index) PetscFunctionReturn(0); 2989d4afb720SToby Isaac SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid index or sum for length 0 barycentric coordinate"); 2990d4afb720SToby Isaac } 2991d4afb720SToby Isaac for (c = 1, total = 1; c <= len; c++) { 2992d4afb720SToby Isaac /* total is the number of ways to have a tuple of length c with sum */ 2993d4afb720SToby Isaac if (index < total) break; 2994d4afb720SToby Isaac total = (total * (sum + c)) / c; 2995d4afb720SToby Isaac } 299608401ef6SPierre Jolivet PetscCheck(c <= len, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "index out of range"); 2997d4afb720SToby Isaac for (d = c; d < len; d++) coord[d] = 0; 2998d4afb720SToby Isaac for (s = 0, subtotal = 1, nexttotal = 1; c > 0;) { 2999d4afb720SToby Isaac /* subtotal is the number of ways to have a tuple of length c with sum s */ 3000d4afb720SToby Isaac /* nexttotal is the number of ways to have a tuple of length c-1 with sum s */ 3001d4afb720SToby Isaac if ((index + subtotal) >= total) { 3002d4afb720SToby Isaac coord[--c] = sum - s; 3003d4afb720SToby Isaac index -= (total - subtotal); 3004d4afb720SToby Isaac sum = s; 3005d4afb720SToby Isaac total = nexttotal; 3006d4afb720SToby Isaac subtotal = 1; 3007d4afb720SToby Isaac nexttotal = 1; 3008d4afb720SToby Isaac s = 0; 3009d4afb720SToby Isaac } else { 3010d4afb720SToby Isaac subtotal = (subtotal * (c + s)) / (s + 1); 3011d4afb720SToby Isaac nexttotal = (nexttotal * (c - 1 + s)) / (s + 1); 3012d4afb720SToby Isaac s++; 3013d4afb720SToby Isaac } 3014d4afb720SToby Isaac } 3015d4afb720SToby Isaac PetscFunctionReturn(0); 3016d4afb720SToby Isaac } 3017d4afb720SToby Isaac 3018d4afb720SToby Isaac /*@ 3019d4afb720SToby Isaac PetscDTBaryToIndex - convert a barycentric coordinate to an index 3020d4afb720SToby Isaac 3021d4afb720SToby Isaac Input Parameters: 3022d4afb720SToby 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) 3023d4afb720SToby Isaac . sum - the value that the sum of the barycentric coordinates (which will be non-negative integers) should sum to 3024d4afb720SToby Isaac - coord - a barycentric coordinate with the given length and sum 3025d4afb720SToby Isaac 3026d4afb720SToby Isaac Output Parameter: 3027d4afb720SToby Isaac . index - the unique index for the coordinate, >= 0 and < Binomial(len - 1 + sum, sum) 3028d4afb720SToby Isaac 3029d4afb720SToby Isaac Level: beginner 3030d4afb720SToby Isaac 3031d4afb720SToby Isaac Note: the indices map to barycentric coordinates in lexicographic order, where the first index is the 3032d4afb720SToby Isaac least significant and the last index is the most significant. 3033d4afb720SToby Isaac 3034db781477SPatrick Sanan .seealso: `PetscDTIndexToBary` 3035d4afb720SToby Isaac @*/ 3036*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscDTBaryToIndex(PetscInt len, PetscInt sum, const PetscInt coord[], PetscInt *index) 3037*d71ae5a4SJacob Faibussowitsch { 3038d4afb720SToby Isaac PetscInt c; 3039d4afb720SToby Isaac PetscInt i; 3040d4afb720SToby Isaac PetscInt total; 3041d4afb720SToby Isaac 3042d4afb720SToby Isaac PetscFunctionBeginHot; 304308401ef6SPierre Jolivet PetscCheck(len >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "length must be non-negative"); 3044d4afb720SToby Isaac if (!len) { 3045d4afb720SToby Isaac if (!sum) { 3046d4afb720SToby Isaac *index = 0; 3047d4afb720SToby Isaac PetscFunctionReturn(0); 3048d4afb720SToby Isaac } 3049d4afb720SToby Isaac SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid index or sum for length 0 barycentric coordinate"); 3050d4afb720SToby Isaac } 3051d4afb720SToby Isaac for (c = 1, total = 1; c < len; c++) total = (total * (sum + c)) / c; 3052d4afb720SToby Isaac i = total - 1; 3053d4afb720SToby Isaac c = len - 1; 3054d4afb720SToby Isaac sum -= coord[c]; 3055d4afb720SToby Isaac while (sum > 0) { 3056d4afb720SToby Isaac PetscInt subtotal; 3057d4afb720SToby Isaac PetscInt s; 3058d4afb720SToby Isaac 3059d4afb720SToby Isaac for (s = 1, subtotal = 1; s < sum; s++) subtotal = (subtotal * (c + s)) / s; 3060d4afb720SToby Isaac i -= subtotal; 3061d4afb720SToby Isaac sum -= coord[--c]; 3062d4afb720SToby Isaac } 3063d4afb720SToby Isaac *index = i; 3064d4afb720SToby Isaac PetscFunctionReturn(0); 3065d4afb720SToby Isaac } 3066