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