xref: /petsc/src/dm/dt/interface/dt.c (revision 94e21283241cd5b3fb318e27fae422acd420d8d9)
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 
15e6a796c3SToby Isaac static PetscBool GolubWelschCite       = PETSC_FALSE;
16e6a796c3SToby Isaac const char       GolubWelschCitation[] = "@article{GolubWelsch1969,\n"
170bfcf5a5SMatthew G. Knepley                                          "  author  = {Golub and Welsch},\n"
180bfcf5a5SMatthew G. Knepley                                          "  title   = {Calculation of Quadrature Rules},\n"
190bfcf5a5SMatthew G. Knepley                                          "  journal = {Math. Comp.},\n"
200bfcf5a5SMatthew G. Knepley                                          "  volume  = {23},\n"
210bfcf5a5SMatthew G. Knepley                                          "  number  = {106},\n"
220bfcf5a5SMatthew G. Knepley                                          "  pages   = {221--230},\n"
230bfcf5a5SMatthew G. Knepley                                          "  year    = {1969}\n}\n";
240bfcf5a5SMatthew G. Knepley 
25*94e21283SToby Isaac /* Numerical tests in src/dm/dt/examples/tests/ex1.c show that when computing the nodes and weights of Gauss-Jacobi
26*94e21283SToby Isaac    quadrature rules:
27e6a796c3SToby Isaac 
28*94e21283SToby Isaac    - in double precision, Newton's method and Golub & Welsch both work for moderate degrees (< 100),
29*94e21283SToby Isaac    - in single precision, Newton's method starts producing incorrect roots around n = 15, but
30*94e21283SToby Isaac      the weights from Golub & Welsch become a problem before then: they produces errors
31*94e21283SToby Isaac      in computing the Jacobi-polynomial Gram matrix around n = 6.
32*94e21283SToby Isaac 
33*94e21283SToby Isaac    So we default to Newton's method (required fewer dependencies) */
34*94e21283SToby Isaac PetscBool PetscDTGaussQuadratureNewton_Internal = PETSC_TRUE;
352cd22861SMatthew G. Knepley 
362cd22861SMatthew G. Knepley PetscClassId PETSCQUADRATURE_CLASSID = 0;
372cd22861SMatthew G. Knepley 
3840d8ff71SMatthew G. Knepley /*@
3940d8ff71SMatthew G. Knepley   PetscQuadratureCreate - Create a PetscQuadrature object
4040d8ff71SMatthew G. Knepley 
41d083f849SBarry Smith   Collective
4240d8ff71SMatthew G. Knepley 
4340d8ff71SMatthew G. Knepley   Input Parameter:
4440d8ff71SMatthew G. Knepley . comm - The communicator for the PetscQuadrature object
4540d8ff71SMatthew G. Knepley 
4640d8ff71SMatthew G. Knepley   Output Parameter:
4740d8ff71SMatthew G. Knepley . q  - The PetscQuadrature object
4840d8ff71SMatthew G. Knepley 
4940d8ff71SMatthew G. Knepley   Level: beginner
5040d8ff71SMatthew G. Knepley 
5140d8ff71SMatthew G. Knepley .seealso: PetscQuadratureDestroy(), PetscQuadratureGetData()
5240d8ff71SMatthew G. Knepley @*/
5321454ff5SMatthew G. Knepley PetscErrorCode PetscQuadratureCreate(MPI_Comm comm, PetscQuadrature *q)
5421454ff5SMatthew G. Knepley {
5521454ff5SMatthew G. Knepley   PetscErrorCode ierr;
5621454ff5SMatthew G. Knepley 
5721454ff5SMatthew G. Knepley   PetscFunctionBegin;
5821454ff5SMatthew G. Knepley   PetscValidPointer(q, 2);
592cd22861SMatthew G. Knepley   ierr = DMInitializePackage();CHKERRQ(ierr);
602cd22861SMatthew G. Knepley   ierr = PetscHeaderCreate(*q,PETSCQUADRATURE_CLASSID,"PetscQuadrature","Quadrature","DT",comm,PetscQuadratureDestroy,PetscQuadratureView);CHKERRQ(ierr);
6121454ff5SMatthew G. Knepley   (*q)->dim       = -1;
62a6b92713SMatthew G. Knepley   (*q)->Nc        =  1;
63bcede257SMatthew G. Knepley   (*q)->order     = -1;
6421454ff5SMatthew G. Knepley   (*q)->numPoints = 0;
6521454ff5SMatthew G. Knepley   (*q)->points    = NULL;
6621454ff5SMatthew G. Knepley   (*q)->weights   = NULL;
6721454ff5SMatthew G. Knepley   PetscFunctionReturn(0);
6821454ff5SMatthew G. Knepley }
6921454ff5SMatthew G. Knepley 
70c9638911SMatthew G. Knepley /*@
71c9638911SMatthew G. Knepley   PetscQuadratureDuplicate - Create a deep copy of the PetscQuadrature object
72c9638911SMatthew G. Knepley 
73d083f849SBarry Smith   Collective on q
74c9638911SMatthew G. Knepley 
75c9638911SMatthew G. Knepley   Input Parameter:
76c9638911SMatthew G. Knepley . q  - The PetscQuadrature object
77c9638911SMatthew G. Knepley 
78c9638911SMatthew G. Knepley   Output Parameter:
79c9638911SMatthew G. Knepley . r  - The new PetscQuadrature object
80c9638911SMatthew G. Knepley 
81c9638911SMatthew G. Knepley   Level: beginner
82c9638911SMatthew G. Knepley 
83c9638911SMatthew G. Knepley .seealso: PetscQuadratureCreate(), PetscQuadratureDestroy(), PetscQuadratureGetData()
84c9638911SMatthew G. Knepley @*/
85c9638911SMatthew G. Knepley PetscErrorCode PetscQuadratureDuplicate(PetscQuadrature q, PetscQuadrature *r)
86c9638911SMatthew G. Knepley {
87a6b92713SMatthew G. Knepley   PetscInt         order, dim, Nc, Nq;
88c9638911SMatthew G. Knepley   const PetscReal *points, *weights;
89c9638911SMatthew G. Knepley   PetscReal       *p, *w;
90c9638911SMatthew G. Knepley   PetscErrorCode   ierr;
91c9638911SMatthew G. Knepley 
92c9638911SMatthew G. Knepley   PetscFunctionBegin;
93c9638911SMatthew G. Knepley   PetscValidPointer(q, 2);
94c9638911SMatthew G. Knepley   ierr = PetscQuadratureCreate(PetscObjectComm((PetscObject) q), r);CHKERRQ(ierr);
95c9638911SMatthew G. Knepley   ierr = PetscQuadratureGetOrder(q, &order);CHKERRQ(ierr);
96c9638911SMatthew G. Knepley   ierr = PetscQuadratureSetOrder(*r, order);CHKERRQ(ierr);
97a6b92713SMatthew G. Knepley   ierr = PetscQuadratureGetData(q, &dim, &Nc, &Nq, &points, &weights);CHKERRQ(ierr);
98c9638911SMatthew G. Knepley   ierr = PetscMalloc1(Nq*dim, &p);CHKERRQ(ierr);
99f0a0bfafSMatthew G. Knepley   ierr = PetscMalloc1(Nq*Nc, &w);CHKERRQ(ierr);
100580bdb30SBarry Smith   ierr = PetscArraycpy(p, points, Nq*dim);CHKERRQ(ierr);
101580bdb30SBarry Smith   ierr = PetscArraycpy(w, weights, Nc * Nq);CHKERRQ(ierr);
102a6b92713SMatthew G. Knepley   ierr = PetscQuadratureSetData(*r, dim, Nc, Nq, p, w);CHKERRQ(ierr);
103c9638911SMatthew G. Knepley   PetscFunctionReturn(0);
104c9638911SMatthew G. Knepley }
105c9638911SMatthew G. Knepley 
10640d8ff71SMatthew G. Knepley /*@
10740d8ff71SMatthew G. Knepley   PetscQuadratureDestroy - Destroys a PetscQuadrature object
10840d8ff71SMatthew G. Knepley 
109d083f849SBarry Smith   Collective on q
11040d8ff71SMatthew G. Knepley 
11140d8ff71SMatthew G. Knepley   Input Parameter:
11240d8ff71SMatthew G. Knepley . q  - The PetscQuadrature object
11340d8ff71SMatthew G. Knepley 
11440d8ff71SMatthew G. Knepley   Level: beginner
11540d8ff71SMatthew G. Knepley 
11640d8ff71SMatthew G. Knepley .seealso: PetscQuadratureCreate(), PetscQuadratureGetData()
11740d8ff71SMatthew G. Knepley @*/
118bfa639d9SMatthew G. Knepley PetscErrorCode PetscQuadratureDestroy(PetscQuadrature *q)
119bfa639d9SMatthew G. Knepley {
120bfa639d9SMatthew G. Knepley   PetscErrorCode ierr;
121bfa639d9SMatthew G. Knepley 
122bfa639d9SMatthew G. Knepley   PetscFunctionBegin;
12321454ff5SMatthew G. Knepley   if (!*q) PetscFunctionReturn(0);
1242cd22861SMatthew G. Knepley   PetscValidHeaderSpecific((*q),PETSCQUADRATURE_CLASSID,1);
12521454ff5SMatthew G. Knepley   if (--((PetscObject)(*q))->refct > 0) {
12621454ff5SMatthew G. Knepley     *q = NULL;
12721454ff5SMatthew G. Knepley     PetscFunctionReturn(0);
12821454ff5SMatthew G. Knepley   }
12921454ff5SMatthew G. Knepley   ierr = PetscFree((*q)->points);CHKERRQ(ierr);
13021454ff5SMatthew G. Knepley   ierr = PetscFree((*q)->weights);CHKERRQ(ierr);
13121454ff5SMatthew G. Knepley   ierr = PetscHeaderDestroy(q);CHKERRQ(ierr);
13221454ff5SMatthew G. Knepley   PetscFunctionReturn(0);
13321454ff5SMatthew G. Knepley }
13421454ff5SMatthew G. Knepley 
135bcede257SMatthew G. Knepley /*@
136a6b92713SMatthew G. Knepley   PetscQuadratureGetOrder - Return the order of the method
137bcede257SMatthew G. Knepley 
138bcede257SMatthew G. Knepley   Not collective
139bcede257SMatthew G. Knepley 
140bcede257SMatthew G. Knepley   Input Parameter:
141bcede257SMatthew G. Knepley . q - The PetscQuadrature object
142bcede257SMatthew G. Knepley 
143bcede257SMatthew G. Knepley   Output Parameter:
144bcede257SMatthew G. Knepley . order - The order of the quadrature, i.e. the highest degree polynomial that is exactly integrated
145bcede257SMatthew G. Knepley 
146bcede257SMatthew G. Knepley   Level: intermediate
147bcede257SMatthew G. Knepley 
148bcede257SMatthew G. Knepley .seealso: PetscQuadratureSetOrder(), PetscQuadratureGetData(), PetscQuadratureSetData()
149bcede257SMatthew G. Knepley @*/
150bcede257SMatthew G. Knepley PetscErrorCode PetscQuadratureGetOrder(PetscQuadrature q, PetscInt *order)
151bcede257SMatthew G. Knepley {
152bcede257SMatthew G. Knepley   PetscFunctionBegin;
1532cd22861SMatthew G. Knepley   PetscValidHeaderSpecific(q, PETSCQUADRATURE_CLASSID, 1);
154bcede257SMatthew G. Knepley   PetscValidPointer(order, 2);
155bcede257SMatthew G. Knepley   *order = q->order;
156bcede257SMatthew G. Knepley   PetscFunctionReturn(0);
157bcede257SMatthew G. Knepley }
158bcede257SMatthew G. Knepley 
159bcede257SMatthew G. Knepley /*@
160a6b92713SMatthew G. Knepley   PetscQuadratureSetOrder - Return the order of the method
161bcede257SMatthew G. Knepley 
162bcede257SMatthew G. Knepley   Not collective
163bcede257SMatthew G. Knepley 
164bcede257SMatthew G. Knepley   Input Parameters:
165bcede257SMatthew G. Knepley + q - The PetscQuadrature object
166bcede257SMatthew G. Knepley - order - The order of the quadrature, i.e. the highest degree polynomial that is exactly integrated
167bcede257SMatthew G. Knepley 
168bcede257SMatthew G. Knepley   Level: intermediate
169bcede257SMatthew G. Knepley 
170bcede257SMatthew G. Knepley .seealso: PetscQuadratureGetOrder(), PetscQuadratureGetData(), PetscQuadratureSetData()
171bcede257SMatthew G. Knepley @*/
172bcede257SMatthew G. Knepley PetscErrorCode PetscQuadratureSetOrder(PetscQuadrature q, PetscInt order)
173bcede257SMatthew G. Knepley {
174bcede257SMatthew G. Knepley   PetscFunctionBegin;
1752cd22861SMatthew G. Knepley   PetscValidHeaderSpecific(q, PETSCQUADRATURE_CLASSID, 1);
176bcede257SMatthew G. Knepley   q->order = order;
177bcede257SMatthew G. Knepley   PetscFunctionReturn(0);
178bcede257SMatthew G. Knepley }
179bcede257SMatthew G. Knepley 
180a6b92713SMatthew G. Knepley /*@
181a6b92713SMatthew G. Knepley   PetscQuadratureGetNumComponents - Return the number of components for functions to be integrated
182a6b92713SMatthew G. Knepley 
183a6b92713SMatthew G. Knepley   Not collective
184a6b92713SMatthew G. Knepley 
185a6b92713SMatthew G. Knepley   Input Parameter:
186a6b92713SMatthew G. Knepley . q - The PetscQuadrature object
187a6b92713SMatthew G. Knepley 
188a6b92713SMatthew G. Knepley   Output Parameter:
189a6b92713SMatthew G. Knepley . Nc - The number of components
190a6b92713SMatthew G. Knepley 
191a6b92713SMatthew G. Knepley   Note: We are performing an integral int f(x) . w(x) dx, where both f and w (the weight) have Nc components.
192a6b92713SMatthew G. Knepley 
193a6b92713SMatthew G. Knepley   Level: intermediate
194a6b92713SMatthew G. Knepley 
195a6b92713SMatthew G. Knepley .seealso: PetscQuadratureSetNumComponents(), PetscQuadratureGetData(), PetscQuadratureSetData()
196a6b92713SMatthew G. Knepley @*/
197a6b92713SMatthew G. Knepley PetscErrorCode PetscQuadratureGetNumComponents(PetscQuadrature q, PetscInt *Nc)
198a6b92713SMatthew G. Knepley {
199a6b92713SMatthew G. Knepley   PetscFunctionBegin;
2002cd22861SMatthew G. Knepley   PetscValidHeaderSpecific(q, PETSCQUADRATURE_CLASSID, 1);
201a6b92713SMatthew G. Knepley   PetscValidPointer(Nc, 2);
202a6b92713SMatthew G. Knepley   *Nc = q->Nc;
203a6b92713SMatthew G. Knepley   PetscFunctionReturn(0);
204a6b92713SMatthew G. Knepley }
205a6b92713SMatthew G. Knepley 
206a6b92713SMatthew G. Knepley /*@
207a6b92713SMatthew G. Knepley   PetscQuadratureSetNumComponents - Return the number of components for functions to be integrated
208a6b92713SMatthew G. Knepley 
209a6b92713SMatthew G. Knepley   Not collective
210a6b92713SMatthew G. Knepley 
211a6b92713SMatthew G. Knepley   Input Parameters:
212a6b92713SMatthew G. Knepley + q  - The PetscQuadrature object
213a6b92713SMatthew G. Knepley - Nc - The number of components
214a6b92713SMatthew G. Knepley 
215a6b92713SMatthew G. Knepley   Note: We are performing an integral int f(x) . w(x) dx, where both f and w (the weight) have Nc components.
216a6b92713SMatthew G. Knepley 
217a6b92713SMatthew G. Knepley   Level: intermediate
218a6b92713SMatthew G. Knepley 
219a6b92713SMatthew G. Knepley .seealso: PetscQuadratureGetNumComponents(), PetscQuadratureGetData(), PetscQuadratureSetData()
220a6b92713SMatthew G. Knepley @*/
221a6b92713SMatthew G. Knepley PetscErrorCode PetscQuadratureSetNumComponents(PetscQuadrature q, PetscInt Nc)
222a6b92713SMatthew G. Knepley {
223a6b92713SMatthew G. Knepley   PetscFunctionBegin;
2242cd22861SMatthew G. Knepley   PetscValidHeaderSpecific(q, PETSCQUADRATURE_CLASSID, 1);
225a6b92713SMatthew G. Knepley   q->Nc = Nc;
226a6b92713SMatthew G. Knepley   PetscFunctionReturn(0);
227a6b92713SMatthew G. Knepley }
228a6b92713SMatthew G. Knepley 
22940d8ff71SMatthew G. Knepley /*@C
23040d8ff71SMatthew G. Knepley   PetscQuadratureGetData - Returns the data defining the quadrature
23140d8ff71SMatthew G. Knepley 
23240d8ff71SMatthew G. Knepley   Not collective
23340d8ff71SMatthew G. Knepley 
23440d8ff71SMatthew G. Knepley   Input Parameter:
23540d8ff71SMatthew G. Knepley . q  - The PetscQuadrature object
23640d8ff71SMatthew G. Knepley 
23740d8ff71SMatthew G. Knepley   Output Parameters:
23840d8ff71SMatthew G. Knepley + dim - The spatial dimension
239805e7170SToby Isaac . Nc - The number of components
24040d8ff71SMatthew G. Knepley . npoints - The number of quadrature points
24140d8ff71SMatthew G. Knepley . points - The coordinates of each quadrature point
24240d8ff71SMatthew G. Knepley - weights - The weight of each quadrature point
24340d8ff71SMatthew G. Knepley 
24440d8ff71SMatthew G. Knepley   Level: intermediate
24540d8ff71SMatthew G. Knepley 
24695452b02SPatrick Sanan   Fortran Notes:
24795452b02SPatrick Sanan     From Fortran you must call PetscQuadratureRestoreData() when you are done with the data
2481fd49c25SBarry Smith 
24940d8ff71SMatthew G. Knepley .seealso: PetscQuadratureCreate(), PetscQuadratureSetData()
25040d8ff71SMatthew G. Knepley @*/
251a6b92713SMatthew G. Knepley PetscErrorCode PetscQuadratureGetData(PetscQuadrature q, PetscInt *dim, PetscInt *Nc, PetscInt *npoints, const PetscReal *points[], const PetscReal *weights[])
25221454ff5SMatthew G. Knepley {
25321454ff5SMatthew G. Knepley   PetscFunctionBegin;
2542cd22861SMatthew G. Knepley   PetscValidHeaderSpecific(q, PETSCQUADRATURE_CLASSID, 1);
25521454ff5SMatthew G. Knepley   if (dim) {
25621454ff5SMatthew G. Knepley     PetscValidPointer(dim, 2);
25721454ff5SMatthew G. Knepley     *dim = q->dim;
25821454ff5SMatthew G. Knepley   }
259a6b92713SMatthew G. Knepley   if (Nc) {
260a6b92713SMatthew G. Knepley     PetscValidPointer(Nc, 3);
261a6b92713SMatthew G. Knepley     *Nc = q->Nc;
262a6b92713SMatthew G. Knepley   }
26321454ff5SMatthew G. Knepley   if (npoints) {
264a6b92713SMatthew G. Knepley     PetscValidPointer(npoints, 4);
26521454ff5SMatthew G. Knepley     *npoints = q->numPoints;
26621454ff5SMatthew G. Knepley   }
26721454ff5SMatthew G. Knepley   if (points) {
268a6b92713SMatthew G. Knepley     PetscValidPointer(points, 5);
26921454ff5SMatthew G. Knepley     *points = q->points;
27021454ff5SMatthew G. Knepley   }
27121454ff5SMatthew G. Knepley   if (weights) {
272a6b92713SMatthew G. Knepley     PetscValidPointer(weights, 6);
27321454ff5SMatthew G. Knepley     *weights = q->weights;
27421454ff5SMatthew G. Knepley   }
27521454ff5SMatthew G. Knepley   PetscFunctionReturn(0);
27621454ff5SMatthew G. Knepley }
27721454ff5SMatthew G. Knepley 
278907761f8SToby Isaac static PetscErrorCode PetscDTJacobianInverse_Internal(PetscInt m, PetscInt n, const PetscReal J[], PetscReal Jinv[])
279907761f8SToby Isaac {
280907761f8SToby Isaac   PetscScalar    *Js, *Jinvs;
281907761f8SToby Isaac   PetscInt       i, j, k;
282907761f8SToby Isaac   PetscBLASInt   bm, bn, info;
283907761f8SToby Isaac   PetscErrorCode ierr;
284907761f8SToby Isaac 
285907761f8SToby Isaac   PetscFunctionBegin;
286907761f8SToby Isaac   ierr = PetscBLASIntCast(m, &bm);CHKERRQ(ierr);
287907761f8SToby Isaac   ierr = PetscBLASIntCast(n, &bn);CHKERRQ(ierr);
288907761f8SToby Isaac #if defined(PETSC_USE_COMPLEX)
289907761f8SToby Isaac   ierr = PetscMalloc2(m*n, &Js, m*n, &Jinvs);CHKERRQ(ierr);
29028222859SToby Isaac   for (i = 0; i < m*n; i++) Js[i] = J[i];
291907761f8SToby Isaac #else
292907761f8SToby Isaac   Js = (PetscReal *) J;
293907761f8SToby Isaac   Jinvs = Jinv;
294907761f8SToby Isaac #endif
295907761f8SToby Isaac   if (m == n) {
296907761f8SToby Isaac     PetscBLASInt *pivots;
297907761f8SToby Isaac     PetscScalar *W;
298907761f8SToby Isaac 
299907761f8SToby Isaac     ierr = PetscMalloc2(m, &pivots, m, &W);CHKERRQ(ierr);
300907761f8SToby Isaac 
301907761f8SToby Isaac     ierr = PetscArraycpy(Jinvs, Js, m * m);CHKERRQ(ierr);
302907761f8SToby Isaac     PetscStackCallBLAS("LAPACKgetrf", LAPACKgetrf_(&bm, &bm, Jinvs, &bm, pivots, &info));
303907761f8SToby Isaac     if (info) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error returned from LAPACKgetrf %D",(PetscInt)info);
304907761f8SToby Isaac     PetscStackCallBLAS("LAPACKgetri", LAPACKgetri_(&bm, Jinvs, &bm, pivots, W, &bm, &info));
305907761f8SToby Isaac     if (info) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error returned from LAPACKgetri %D",(PetscInt)info);
306907761f8SToby Isaac     ierr = PetscFree2(pivots, W);CHKERRQ(ierr);
307907761f8SToby Isaac   } else if (m < n) {
308907761f8SToby Isaac     PetscScalar *JJT;
309907761f8SToby Isaac     PetscBLASInt *pivots;
310907761f8SToby Isaac     PetscScalar *W;
311907761f8SToby Isaac 
312907761f8SToby Isaac     ierr = PetscMalloc1(m*m, &JJT);CHKERRQ(ierr);
313907761f8SToby Isaac     ierr = PetscMalloc2(m, &pivots, m, &W);CHKERRQ(ierr);
314907761f8SToby Isaac     for (i = 0; i < m; i++) {
315907761f8SToby Isaac       for (j = 0; j < m; j++) {
316907761f8SToby Isaac         PetscScalar val = 0.;
317907761f8SToby Isaac 
318907761f8SToby Isaac         for (k = 0; k < n; k++) val += Js[i * n + k] * Js[j * n + k];
319907761f8SToby Isaac         JJT[i * m + j] = val;
320907761f8SToby Isaac       }
321907761f8SToby Isaac     }
322907761f8SToby Isaac 
323907761f8SToby Isaac     PetscStackCallBLAS("LAPACKgetrf", LAPACKgetrf_(&bm, &bm, JJT, &bm, pivots, &info));
324907761f8SToby Isaac     if (info) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error returned from LAPACKgetrf %D",(PetscInt)info);
325907761f8SToby Isaac     PetscStackCallBLAS("LAPACKgetri", LAPACKgetri_(&bm, JJT, &bm, pivots, W, &bm, &info));
326907761f8SToby Isaac     if (info) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error returned from LAPACKgetri %D",(PetscInt)info);
327907761f8SToby Isaac     for (i = 0; i < n; i++) {
328907761f8SToby Isaac       for (j = 0; j < m; j++) {
329907761f8SToby Isaac         PetscScalar val = 0.;
330907761f8SToby Isaac 
331907761f8SToby Isaac         for (k = 0; k < m; k++) val += Js[k * n + i] * JJT[k * m + j];
332907761f8SToby Isaac         Jinvs[i * m + j] = val;
333907761f8SToby Isaac       }
334907761f8SToby Isaac     }
335907761f8SToby Isaac     ierr = PetscFree2(pivots, W);CHKERRQ(ierr);
336907761f8SToby Isaac     ierr = PetscFree(JJT);CHKERRQ(ierr);
337907761f8SToby Isaac   } else {
338907761f8SToby Isaac     PetscScalar *JTJ;
339907761f8SToby Isaac     PetscBLASInt *pivots;
340907761f8SToby Isaac     PetscScalar *W;
341907761f8SToby Isaac 
342907761f8SToby Isaac     ierr = PetscMalloc1(n*n, &JTJ);CHKERRQ(ierr);
343907761f8SToby Isaac     ierr = PetscMalloc2(n, &pivots, n, &W);CHKERRQ(ierr);
344907761f8SToby Isaac     for (i = 0; i < n; i++) {
345907761f8SToby Isaac       for (j = 0; j < n; j++) {
346907761f8SToby Isaac         PetscScalar val = 0.;
347907761f8SToby Isaac 
348907761f8SToby Isaac         for (k = 0; k < m; k++) val += Js[k * n + i] * Js[k * n + j];
349907761f8SToby Isaac         JTJ[i * n + j] = val;
350907761f8SToby Isaac       }
351907761f8SToby Isaac     }
352907761f8SToby Isaac 
353907761f8SToby Isaac     PetscStackCallBLAS("LAPACKgetrf", LAPACKgetrf_(&bn, &bn, JTJ, &bm, pivots, &info));
354907761f8SToby Isaac     if (info) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error returned from LAPACKgetrf %D",(PetscInt)info);
355907761f8SToby Isaac     PetscStackCallBLAS("LAPACKgetri", LAPACKgetri_(&bn, JTJ, &bn, pivots, W, &bn, &info));
356907761f8SToby Isaac     if (info) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error returned from LAPACKgetri %D",(PetscInt)info);
357907761f8SToby Isaac     for (i = 0; i < n; i++) {
358907761f8SToby Isaac       for (j = 0; j < m; j++) {
359907761f8SToby Isaac         PetscScalar val = 0.;
360907761f8SToby Isaac 
361907761f8SToby Isaac         for (k = 0; k < n; k++) val += JTJ[i * n + k] * Js[j * n + k];
362907761f8SToby Isaac         Jinvs[i * m + j] = val;
363907761f8SToby Isaac       }
364907761f8SToby Isaac     }
365907761f8SToby Isaac     ierr = PetscFree2(pivots, W);CHKERRQ(ierr);
366907761f8SToby Isaac     ierr = PetscFree(JTJ);CHKERRQ(ierr);
367907761f8SToby Isaac   }
368907761f8SToby Isaac #if defined(PETSC_USE_COMPLEX)
36928222859SToby Isaac   for (i = 0; i < m*n; i++) Jinv[i] = PetscRealPart(Jinvs[i]);
370907761f8SToby Isaac   ierr = PetscFree2(Js, Jinvs);CHKERRQ(ierr);
371907761f8SToby Isaac #endif
372907761f8SToby Isaac   PetscFunctionReturn(0);
373907761f8SToby Isaac }
374907761f8SToby Isaac 
375907761f8SToby Isaac /*@
376907761f8SToby Isaac    PetscQuadraturePushForward - Push forward a quadrature functional under an affine transformation.
377907761f8SToby Isaac 
378907761f8SToby Isaac    Collecive on PetscQuadrature
379907761f8SToby Isaac 
380907761f8SToby Isaac    Input Arguments:
381907761f8SToby Isaac +  q - the quadrature functional
382907761f8SToby Isaac .  imageDim - the dimension of the image of the transformation
383907761f8SToby Isaac .  origin - a point in the original space
384907761f8SToby Isaac .  originImage - the image of the origin under the transformation
385907761f8SToby Isaac .  J - the Jacobian of the image: an [imageDim x dim] matrix in row major order
38628222859SToby 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]
387907761f8SToby Isaac 
388907761f8SToby Isaac    Output Arguments:
389907761f8SToby 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.
390907761f8SToby Isaac 
391907761f8SToby 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.
392907761f8SToby Isaac 
393907761f8SToby Isaac .seealso: PetscDTAltVPullback(), PetscDTAltVPullbackMatrix()
394907761f8SToby Isaac @*/
39528222859SToby Isaac PetscErrorCode PetscQuadraturePushForward(PetscQuadrature q, PetscInt imageDim, const PetscReal origin[], const PetscReal originImage[], const PetscReal J[], PetscInt formDegree, PetscQuadrature *Jinvstarq)
396907761f8SToby Isaac {
397907761f8SToby Isaac   PetscInt         dim, Nc, imageNc, formSize, Ncopies, imageFormSize, Npoints, pt, i, j, c;
398907761f8SToby Isaac   const PetscReal *points;
399907761f8SToby Isaac   const PetscReal *weights;
400907761f8SToby Isaac   PetscReal       *imagePoints, *imageWeights;
401907761f8SToby Isaac   PetscReal       *Jinv;
402907761f8SToby Isaac   PetscReal       *Jinvstar;
403907761f8SToby Isaac   PetscErrorCode   ierr;
404907761f8SToby Isaac 
405907761f8SToby Isaac   PetscFunctionBegin;
406907761f8SToby Isaac   PetscValidHeaderSpecific(q, PETSC_OBJECT_CLASSID, 1);
40728222859SToby Isaac   if (imageDim < PetscAbsInt(formDegree)) SETERRQ2(PetscObjectComm((PetscObject)q), PETSC_ERR_ARG_INCOMP, "Cannot represent a %D-form in %D dimensions", PetscAbsInt(formDegree), imageDim);
408907761f8SToby Isaac   ierr = PetscQuadratureGetData(q, &dim, &Nc, &Npoints, &points, &weights);CHKERRQ(ierr);
40928222859SToby Isaac   ierr = PetscDTBinomialInt(dim, PetscAbsInt(formDegree), &formSize);CHKERRQ(ierr);
410907761f8SToby Isaac   if (Nc % formSize) SETERRQ2(PetscObjectComm((PetscObject)q), PETSC_ERR_ARG_INCOMP, "Number of components %D is not a multiple of formSize %D\n", Nc, formSize);
411907761f8SToby Isaac   Ncopies = Nc / formSize;
41228222859SToby Isaac   ierr = PetscDTBinomialInt(imageDim, PetscAbsInt(formDegree), &imageFormSize);CHKERRQ(ierr);
413907761f8SToby Isaac   imageNc = Ncopies * imageFormSize;
414907761f8SToby Isaac   ierr = PetscMalloc1(Npoints * imageDim, &imagePoints);CHKERRQ(ierr);
415907761f8SToby Isaac   ierr = PetscMalloc1(Npoints * imageNc, &imageWeights);CHKERRQ(ierr);
416907761f8SToby Isaac   ierr = PetscMalloc2(imageDim * dim, &Jinv, formSize * imageFormSize, &Jinvstar);CHKERRQ(ierr);
417907761f8SToby Isaac   ierr = PetscDTJacobianInverse_Internal(dim, imageDim, J, Jinv);CHKERRQ(ierr);
41828222859SToby Isaac   ierr = PetscDTAltVPullbackMatrix(imageDim, dim, Jinv, formDegree, Jinvstar);CHKERRQ(ierr);
419907761f8SToby Isaac   for (pt = 0; pt < Npoints; pt++) {
420907761f8SToby Isaac     const PetscReal *point = &points[pt * dim];
421907761f8SToby Isaac     PetscReal       *imagePoint = &imagePoints[pt * imageDim];
422907761f8SToby Isaac 
423907761f8SToby Isaac     for (i = 0; i < imageDim; i++) {
424907761f8SToby Isaac       PetscReal val = originImage[i];
425907761f8SToby Isaac 
426907761f8SToby Isaac       for (j = 0; j < dim; j++) val += J[i * dim + j] * (point[j] - origin[j]);
427907761f8SToby Isaac       imagePoint[i] = val;
428907761f8SToby Isaac     }
429907761f8SToby Isaac     for (c = 0; c < Ncopies; c++) {
430907761f8SToby Isaac       const PetscReal *form = &weights[pt * Nc + c * formSize];
431907761f8SToby Isaac       PetscReal       *imageForm = &imageWeights[pt * imageNc + c * imageFormSize];
432907761f8SToby Isaac 
433907761f8SToby Isaac       for (i = 0; i < imageFormSize; i++) {
434907761f8SToby Isaac         PetscReal val = 0.;
435907761f8SToby Isaac 
436907761f8SToby Isaac         for (j = 0; j < formSize; j++) val += Jinvstar[i * formSize + j] * form[j];
437907761f8SToby Isaac         imageForm[i] = val;
438907761f8SToby Isaac       }
439907761f8SToby Isaac     }
440907761f8SToby Isaac   }
441907761f8SToby Isaac   ierr = PetscQuadratureCreate(PetscObjectComm((PetscObject)q), Jinvstarq);CHKERRQ(ierr);
442907761f8SToby Isaac   ierr = PetscQuadratureSetData(*Jinvstarq, imageDim, imageNc, Npoints, imagePoints, imageWeights);CHKERRQ(ierr);
443907761f8SToby Isaac   ierr = PetscFree2(Jinv, Jinvstar);CHKERRQ(ierr);
444907761f8SToby Isaac   PetscFunctionReturn(0);
445907761f8SToby Isaac }
446907761f8SToby Isaac 
44740d8ff71SMatthew G. Knepley /*@C
44840d8ff71SMatthew G. Knepley   PetscQuadratureSetData - Sets the data defining the quadrature
44940d8ff71SMatthew G. Knepley 
45040d8ff71SMatthew G. Knepley   Not collective
45140d8ff71SMatthew G. Knepley 
45240d8ff71SMatthew G. Knepley   Input Parameters:
45340d8ff71SMatthew G. Knepley + q  - The PetscQuadrature object
45440d8ff71SMatthew G. Knepley . dim - The spatial dimension
455e2b35d93SBarry Smith . Nc - The number of components
45640d8ff71SMatthew G. Knepley . npoints - The number of quadrature points
45740d8ff71SMatthew G. Knepley . points - The coordinates of each quadrature point
45840d8ff71SMatthew G. Knepley - weights - The weight of each quadrature point
45940d8ff71SMatthew G. Knepley 
460c99e0549SMatthew 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.
461f2fd9e53SMatthew G. Knepley 
46240d8ff71SMatthew G. Knepley   Level: intermediate
46340d8ff71SMatthew G. Knepley 
46440d8ff71SMatthew G. Knepley .seealso: PetscQuadratureCreate(), PetscQuadratureGetData()
46540d8ff71SMatthew G. Knepley @*/
466a6b92713SMatthew G. Knepley PetscErrorCode PetscQuadratureSetData(PetscQuadrature q, PetscInt dim, PetscInt Nc, PetscInt npoints, const PetscReal points[], const PetscReal weights[])
46721454ff5SMatthew G. Knepley {
46821454ff5SMatthew G. Knepley   PetscFunctionBegin;
4692cd22861SMatthew G. Knepley   PetscValidHeaderSpecific(q, PETSCQUADRATURE_CLASSID, 1);
47021454ff5SMatthew G. Knepley   if (dim >= 0)     q->dim       = dim;
471a6b92713SMatthew G. Knepley   if (Nc >= 0)      q->Nc        = Nc;
47221454ff5SMatthew G. Knepley   if (npoints >= 0) q->numPoints = npoints;
47321454ff5SMatthew G. Knepley   if (points) {
47421454ff5SMatthew G. Knepley     PetscValidPointer(points, 4);
47521454ff5SMatthew G. Knepley     q->points = points;
47621454ff5SMatthew G. Knepley   }
47721454ff5SMatthew G. Knepley   if (weights) {
47821454ff5SMatthew G. Knepley     PetscValidPointer(weights, 5);
47921454ff5SMatthew G. Knepley     q->weights = weights;
48021454ff5SMatthew G. Knepley   }
481f9fd7fdbSMatthew G. Knepley   PetscFunctionReturn(0);
482f9fd7fdbSMatthew G. Knepley }
483f9fd7fdbSMatthew G. Knepley 
484d9bac1caSLisandro Dalcin static PetscErrorCode PetscQuadratureView_Ascii(PetscQuadrature quad, PetscViewer v)
485d9bac1caSLisandro Dalcin {
486d9bac1caSLisandro Dalcin   PetscInt          q, d, c;
487d9bac1caSLisandro Dalcin   PetscViewerFormat format;
488d9bac1caSLisandro Dalcin   PetscErrorCode    ierr;
489d9bac1caSLisandro Dalcin 
490d9bac1caSLisandro Dalcin   PetscFunctionBegin;
491c74b4a09SMatthew 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);}
492c74b4a09SMatthew G. Knepley   else              {ierr = PetscViewerASCIIPrintf(v, "Quadrature of order %D on %D points (dim %D)\n", quad->order, quad->numPoints, quad->dim);CHKERRQ(ierr);}
493d9bac1caSLisandro Dalcin   ierr = PetscViewerGetFormat(v, &format);CHKERRQ(ierr);
494d9bac1caSLisandro Dalcin   if (format != PETSC_VIEWER_ASCII_INFO_DETAIL) PetscFunctionReturn(0);
495d9bac1caSLisandro Dalcin   for (q = 0; q < quad->numPoints; ++q) {
496c74b4a09SMatthew G. Knepley     ierr = PetscViewerASCIIPrintf(v, "p%D (", q);CHKERRQ(ierr);
497d9bac1caSLisandro Dalcin     ierr = PetscViewerASCIIUseTabs(v, PETSC_FALSE);CHKERRQ(ierr);
498d9bac1caSLisandro Dalcin     for (d = 0; d < quad->dim; ++d) {
499d9bac1caSLisandro Dalcin       if (d) {ierr = PetscViewerASCIIPrintf(v, ", ");CHKERRQ(ierr);}
500d9bac1caSLisandro Dalcin       ierr = PetscViewerASCIIPrintf(v, "%+g", (double)quad->points[q*quad->dim+d]);CHKERRQ(ierr);
501d9bac1caSLisandro Dalcin     }
502d9bac1caSLisandro Dalcin     ierr = PetscViewerASCIIPrintf(v, ") ");CHKERRQ(ierr);
503c74b4a09SMatthew G. Knepley     if (quad->Nc > 1) {ierr = PetscViewerASCIIPrintf(v, "w%D (", q);CHKERRQ(ierr);}
504d9bac1caSLisandro Dalcin     for (c = 0; c < quad->Nc; ++c) {
505d9bac1caSLisandro Dalcin       if (c) {ierr = PetscViewerASCIIPrintf(v, ", ");CHKERRQ(ierr);}
506c74b4a09SMatthew G. Knepley       ierr = PetscViewerASCIIPrintf(v, "%+g", (double)quad->weights[q*quad->Nc+c]);CHKERRQ(ierr);
507d9bac1caSLisandro Dalcin     }
508d9bac1caSLisandro Dalcin     if (quad->Nc > 1) {ierr = PetscViewerASCIIPrintf(v, ")");CHKERRQ(ierr);}
509d9bac1caSLisandro Dalcin     ierr = PetscViewerASCIIPrintf(v, "\n");CHKERRQ(ierr);
510d9bac1caSLisandro Dalcin     ierr = PetscViewerASCIIUseTabs(v, PETSC_TRUE);CHKERRQ(ierr);
511d9bac1caSLisandro Dalcin   }
512d9bac1caSLisandro Dalcin   PetscFunctionReturn(0);
513d9bac1caSLisandro Dalcin }
514d9bac1caSLisandro Dalcin 
51540d8ff71SMatthew G. Knepley /*@C
51640d8ff71SMatthew G. Knepley   PetscQuadratureView - Views a PetscQuadrature object
51740d8ff71SMatthew G. Knepley 
518d083f849SBarry Smith   Collective on quad
51940d8ff71SMatthew G. Knepley 
52040d8ff71SMatthew G. Knepley   Input Parameters:
521d9bac1caSLisandro Dalcin + quad  - The PetscQuadrature object
52240d8ff71SMatthew G. Knepley - viewer - The PetscViewer object
52340d8ff71SMatthew G. Knepley 
52440d8ff71SMatthew G. Knepley   Level: beginner
52540d8ff71SMatthew G. Knepley 
52640d8ff71SMatthew G. Knepley .seealso: PetscQuadratureCreate(), PetscQuadratureGetData()
52740d8ff71SMatthew G. Knepley @*/
528f9fd7fdbSMatthew G. Knepley PetscErrorCode PetscQuadratureView(PetscQuadrature quad, PetscViewer viewer)
529f9fd7fdbSMatthew G. Knepley {
530d9bac1caSLisandro Dalcin   PetscBool      iascii;
531f9fd7fdbSMatthew G. Knepley   PetscErrorCode ierr;
532f9fd7fdbSMatthew G. Knepley 
533f9fd7fdbSMatthew G. Knepley   PetscFunctionBegin;
534d9bac1caSLisandro Dalcin   PetscValidHeader(quad, 1);
535d9bac1caSLisandro Dalcin   if (viewer) PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
536d9bac1caSLisandro Dalcin   if (!viewer) {ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject) quad), &viewer);CHKERRQ(ierr);}
537d9bac1caSLisandro Dalcin   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
538d9bac1caSLisandro Dalcin   ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
539d9bac1caSLisandro Dalcin   if (iascii) {ierr = PetscQuadratureView_Ascii(quad, viewer);CHKERRQ(ierr);}
540d9bac1caSLisandro Dalcin   ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
541bfa639d9SMatthew G. Knepley   PetscFunctionReturn(0);
542bfa639d9SMatthew G. Knepley }
543bfa639d9SMatthew G. Knepley 
54489710940SMatthew G. Knepley /*@C
54589710940SMatthew G. Knepley   PetscQuadratureExpandComposite - Return a quadrature over the composite element, which has the original quadrature in each subelement
54689710940SMatthew G. Knepley 
54789710940SMatthew G. Knepley   Not collective
54889710940SMatthew G. Knepley 
54989710940SMatthew G. Knepley   Input Parameter:
55089710940SMatthew G. Knepley + q - The original PetscQuadrature
55189710940SMatthew G. Knepley . numSubelements - The number of subelements the original element is divided into
55289710940SMatthew G. Knepley . v0 - An array of the initial points for each subelement
55389710940SMatthew G. Knepley - jac - An array of the Jacobian mappings from the reference to each subelement
55489710940SMatthew G. Knepley 
55589710940SMatthew G. Knepley   Output Parameters:
55689710940SMatthew G. Knepley . dim - The dimension
55789710940SMatthew G. Knepley 
55889710940SMatthew G. Knepley   Note: Together v0 and jac define an affine mapping from the original reference element to each subelement
55989710940SMatthew G. Knepley 
560f5f57ec0SBarry Smith  Not available from Fortran
561f5f57ec0SBarry Smith 
56289710940SMatthew G. Knepley   Level: intermediate
56389710940SMatthew G. Knepley 
56489710940SMatthew G. Knepley .seealso: PetscFECreate(), PetscSpaceGetDimension(), PetscDualSpaceGetDimension()
56589710940SMatthew G. Knepley @*/
56689710940SMatthew G. Knepley PetscErrorCode PetscQuadratureExpandComposite(PetscQuadrature q, PetscInt numSubelements, const PetscReal v0[], const PetscReal jac[], PetscQuadrature *qref)
56789710940SMatthew G. Knepley {
56889710940SMatthew G. Knepley   const PetscReal *points,    *weights;
56989710940SMatthew G. Knepley   PetscReal       *pointsRef, *weightsRef;
570a6b92713SMatthew G. Knepley   PetscInt         dim, Nc, order, npoints, npointsRef, c, p, cp, d, e;
57189710940SMatthew G. Knepley   PetscErrorCode   ierr;
57289710940SMatthew G. Knepley 
57389710940SMatthew G. Knepley   PetscFunctionBegin;
5742cd22861SMatthew G. Knepley   PetscValidHeaderSpecific(q, PETSCQUADRATURE_CLASSID, 1);
57589710940SMatthew G. Knepley   PetscValidPointer(v0, 3);
57689710940SMatthew G. Knepley   PetscValidPointer(jac, 4);
57789710940SMatthew G. Knepley   PetscValidPointer(qref, 5);
57889710940SMatthew G. Knepley   ierr = PetscQuadratureCreate(PETSC_COMM_SELF, qref);CHKERRQ(ierr);
57989710940SMatthew G. Knepley   ierr = PetscQuadratureGetOrder(q, &order);CHKERRQ(ierr);
580a6b92713SMatthew G. Knepley   ierr = PetscQuadratureGetData(q, &dim, &Nc, &npoints, &points, &weights);CHKERRQ(ierr);
58189710940SMatthew G. Knepley   npointsRef = npoints*numSubelements;
58289710940SMatthew G. Knepley   ierr = PetscMalloc1(npointsRef*dim,&pointsRef);CHKERRQ(ierr);
583a6b92713SMatthew G. Knepley   ierr = PetscMalloc1(npointsRef*Nc, &weightsRef);CHKERRQ(ierr);
58489710940SMatthew G. Knepley   for (c = 0; c < numSubelements; ++c) {
58589710940SMatthew G. Knepley     for (p = 0; p < npoints; ++p) {
58689710940SMatthew G. Knepley       for (d = 0; d < dim; ++d) {
58789710940SMatthew G. Knepley         pointsRef[(c*npoints + p)*dim+d] = v0[c*dim+d];
58889710940SMatthew G. Knepley         for (e = 0; e < dim; ++e) {
58989710940SMatthew G. Knepley           pointsRef[(c*npoints + p)*dim+d] += jac[(c*dim + d)*dim+e]*(points[p*dim+e] + 1.0);
59089710940SMatthew G. Knepley         }
59189710940SMatthew G. Knepley       }
59289710940SMatthew G. Knepley       /* Could also use detJ here */
593a6b92713SMatthew G. Knepley       for (cp = 0; cp < Nc; ++cp) weightsRef[(c*npoints+p)*Nc+cp] = weights[p*Nc+cp]/numSubelements;
59489710940SMatthew G. Knepley     }
59589710940SMatthew G. Knepley   }
59689710940SMatthew G. Knepley   ierr = PetscQuadratureSetOrder(*qref, order);CHKERRQ(ierr);
597a6b92713SMatthew G. Knepley   ierr = PetscQuadratureSetData(*qref, dim, Nc, npointsRef, pointsRef, weightsRef);CHKERRQ(ierr);
59889710940SMatthew G. Knepley   PetscFunctionReturn(0);
59989710940SMatthew G. Knepley }
60089710940SMatthew G. Knepley 
601*94e21283SToby Isaac /* Compute the coefficients for the Jacobi polynomial recurrence,
602*94e21283SToby Isaac  *
603*94e21283SToby Isaac  * J^{a,b}_n(x) = (cnm1 + cnm1x * x) * J^{a,b}_{n-1}(x) - cnm2 * J^{a,b}_{n-2}(x).
604*94e21283SToby Isaac  */
605*94e21283SToby Isaac #define PetscDTJacobiRecurrence_Internal(n,a,b,cnm1,cnm1x,cnm2) \
606*94e21283SToby Isaac do {                                                            \
607*94e21283SToby Isaac   PetscReal _a = (a);                                           \
608*94e21283SToby Isaac   PetscReal _b = (b);                                           \
609*94e21283SToby Isaac   PetscReal _n = (n);                                           \
610*94e21283SToby Isaac   if (n == 1) {                                                 \
611*94e21283SToby Isaac     (cnm1) = (_a-_b) * 0.5;                                     \
612*94e21283SToby Isaac     (cnm1x) = (_a+_b+2.)*0.5;                                   \
613*94e21283SToby Isaac     (cnm2) = 0.;                                                \
614*94e21283SToby Isaac   } else {                                                      \
615*94e21283SToby Isaac     PetscReal _2n = _n+_n;                                      \
616*94e21283SToby Isaac     PetscReal _d = (_2n*(_n+_a+_b)*(_2n+_a+_b-2));              \
617*94e21283SToby Isaac     PetscReal _n1 = (_2n+_a+_b-1.)*(_a*_a-_b*_b);               \
618*94e21283SToby Isaac     PetscReal _n1x = (_2n+_a+_b-1.)*(_2n+_a+_b)*(_2n+_a+_b-2);  \
619*94e21283SToby Isaac     PetscReal _n2 = 2.*((_n+_a-1.)*(_n+_b-1.)*(_2n+_a+_b));     \
620*94e21283SToby Isaac     (cnm1) = _n1 / _d;                                          \
621*94e21283SToby Isaac     (cnm1x) = _n1x / _d;                                        \
622*94e21283SToby Isaac     (cnm2) = _n2 / _d;                                          \
623*94e21283SToby Isaac   }                                                             \
624*94e21283SToby Isaac } while (0)
625*94e21283SToby Isaac 
626*94e21283SToby Isaac static PetscErrorCode PetscDTJacobiEval_Internal(PetscInt npoints, PetscReal a, PetscReal b, PetscInt k, const PetscReal *points, PetscInt ndegree, const PetscInt *degrees, PetscReal *p)
627*94e21283SToby Isaac {
628*94e21283SToby Isaac   PetscReal ak, bk;
629*94e21283SToby Isaac   PetscReal abk1;
630*94e21283SToby Isaac   PetscInt i,l,maxdegree;
631*94e21283SToby Isaac 
632*94e21283SToby Isaac   PetscFunctionBegin;
633*94e21283SToby Isaac   maxdegree = degrees[ndegree-1] - k;
634*94e21283SToby Isaac   ak = a + k;
635*94e21283SToby Isaac   bk = b + k;
636*94e21283SToby Isaac   abk1 = a + b + k + 1.;
637*94e21283SToby Isaac   if (maxdegree < 0) {
638*94e21283SToby Isaac     for (i = 0; i < npoints; i++) for (l = 0; l < ndegree; l++) p[i*ndegree+l] = 0.;
639*94e21283SToby Isaac     PetscFunctionReturn(0);
640*94e21283SToby Isaac   }
641*94e21283SToby Isaac   for (i=0; i<npoints; i++) {
642*94e21283SToby Isaac     PetscReal pm1,pm2,x;
643*94e21283SToby Isaac     PetscReal cnm1, cnm1x, cnm2;
644*94e21283SToby Isaac     PetscInt  j,m;
645*94e21283SToby Isaac 
646*94e21283SToby Isaac     x    = points[i];
647*94e21283SToby Isaac     pm2  = 1.;
648*94e21283SToby Isaac     PetscDTJacobiRecurrence_Internal(1,ak,bk,cnm1,cnm1x,cnm2);
649*94e21283SToby Isaac     pm1 = (cnm1 + cnm1x*x);
650*94e21283SToby Isaac     l    = 0;
651*94e21283SToby Isaac     while (l < ndegree && degrees[l] - k < 0) {
652*94e21283SToby Isaac       p[l++] = 0.;
653*94e21283SToby Isaac     }
654*94e21283SToby Isaac     while (l < ndegree && degrees[l] - k == 0) {
655*94e21283SToby Isaac       p[l] = pm2;
656*94e21283SToby Isaac       for (m = 0; m < k; m++) p[l] *= (abk1 + m) * 0.5;
657*94e21283SToby Isaac       l++;
658*94e21283SToby Isaac     }
659*94e21283SToby Isaac     while (l < ndegree && degrees[l] - k == 1) {
660*94e21283SToby Isaac       p[l] = pm1;
661*94e21283SToby Isaac       for (m = 0; m < k; m++) p[l] *= (abk1 + 1 + m) * 0.5;
662*94e21283SToby Isaac       l++;
663*94e21283SToby Isaac     }
664*94e21283SToby Isaac     for (j=2; j<=maxdegree; j++) {
665*94e21283SToby Isaac       PetscReal pp;
666*94e21283SToby Isaac 
667*94e21283SToby Isaac       PetscDTJacobiRecurrence_Internal(j,ak,bk,cnm1,cnm1x,cnm2);
668*94e21283SToby Isaac       pp   = (cnm1 + cnm1x*x)*pm1 - cnm2*pm2;
669*94e21283SToby Isaac       pm2  = pm1;
670*94e21283SToby Isaac       pm1  = pp;
671*94e21283SToby Isaac       while (l < ndegree && degrees[l] - k == j) {
672*94e21283SToby Isaac         p[l] = pp;
673*94e21283SToby Isaac         for (m = 0; m < k; m++) p[l] *= (abk1 + j + m) * 0.5;
674*94e21283SToby Isaac         l++;
675*94e21283SToby Isaac       }
676*94e21283SToby Isaac     }
677*94e21283SToby Isaac     p += ndegree;
678*94e21283SToby Isaac   }
679*94e21283SToby Isaac   PetscFunctionReturn(0);
680*94e21283SToby Isaac }
681*94e21283SToby Isaac 
68237045ce4SJed Brown /*@
683*94e21283SToby Isaac    PetscDTJacobiEval - evaluate Jacobi polynomials for the weight function $(1.+x)^{\alpha} (1.-x)^{\beta}$
684*94e21283SToby Isaac                        at points
685*94e21283SToby Isaac 
686*94e21283SToby Isaac    Not Collective
687*94e21283SToby Isaac 
688*94e21283SToby Isaac    Input Arguments:
689*94e21283SToby Isaac +  npoints - number of spatial points to evaluate at
690*94e21283SToby Isaac .  alpha - the left exponent > -1
691*94e21283SToby Isaac .  beta - the right exponent > -1
692*94e21283SToby Isaac .  points - array of locations to evaluate at
693*94e21283SToby Isaac .  ndegree - number of basis degrees to evaluate
694*94e21283SToby Isaac -  degrees - sorted array of degrees to evaluate
695*94e21283SToby Isaac 
696*94e21283SToby Isaac    Output Arguments:
697*94e21283SToby Isaac +  B - row-oriented basis evaluation matrix B[point*ndegree + degree] (dimension npoints*ndegrees, allocated by caller) (or NULL)
698*94e21283SToby Isaac .  D - row-oriented derivative evaluation matrix (or NULL)
699*94e21283SToby Isaac -  D2 - row-oriented second derivative evaluation matrix (or NULL)
700*94e21283SToby Isaac 
701*94e21283SToby Isaac    Level: intermediate
702*94e21283SToby Isaac 
703*94e21283SToby Isaac .seealso: PetscDTGaussQuadrature()
704*94e21283SToby Isaac @*/
705*94e21283SToby Isaac PetscErrorCode PetscDTJacobiEval(PetscInt npoints,PetscReal alpha, PetscReal beta, const PetscReal *points,PetscInt ndegree,const PetscInt *degrees,PetscReal *B,PetscReal *D,PetscReal *D2)
706*94e21283SToby Isaac {
707*94e21283SToby Isaac   PetscErrorCode ierr;
708*94e21283SToby Isaac 
709*94e21283SToby Isaac   PetscFunctionBegin;
710*94e21283SToby Isaac   if (alpha <= -1.) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"alpha must be > -1.");
711*94e21283SToby Isaac   if (beta <= -1.) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"beta must be > -1.");
712*94e21283SToby Isaac   if (!npoints || !ndegree) PetscFunctionReturn(0);
713*94e21283SToby Isaac   if (B)  {ierr = PetscDTJacobiEval_Internal(npoints, alpha, beta, 0, points, ndegree, degrees, B);CHKERRQ(ierr);}
714*94e21283SToby Isaac   if (D)  {ierr = PetscDTJacobiEval_Internal(npoints, alpha, beta, 1, points, ndegree, degrees, D);CHKERRQ(ierr);}
715*94e21283SToby Isaac   if (D2) {ierr = PetscDTJacobiEval_Internal(npoints, alpha, beta, 2, points, ndegree, degrees, D2);CHKERRQ(ierr);}
716*94e21283SToby Isaac   PetscFunctionReturn(0);
717*94e21283SToby Isaac }
718*94e21283SToby Isaac 
719*94e21283SToby Isaac /*@
720*94e21283SToby Isaac    PetscDTLegendreEval - evaluate Legendre polynomials at points
72137045ce4SJed Brown 
72237045ce4SJed Brown    Not Collective
72337045ce4SJed Brown 
72437045ce4SJed Brown    Input Arguments:
72537045ce4SJed Brown +  npoints - number of spatial points to evaluate at
72637045ce4SJed Brown .  points - array of locations to evaluate at
72737045ce4SJed Brown .  ndegree - number of basis degrees to evaluate
72837045ce4SJed Brown -  degrees - sorted array of degrees to evaluate
72937045ce4SJed Brown 
73037045ce4SJed Brown    Output Arguments:
7310298fd71SBarry Smith +  B - row-oriented basis evaluation matrix B[point*ndegree + degree] (dimension npoints*ndegrees, allocated by caller) (or NULL)
7320298fd71SBarry Smith .  D - row-oriented derivative evaluation matrix (or NULL)
7330298fd71SBarry Smith -  D2 - row-oriented second derivative evaluation matrix (or NULL)
73437045ce4SJed Brown 
73537045ce4SJed Brown    Level: intermediate
73637045ce4SJed Brown 
73737045ce4SJed Brown .seealso: PetscDTGaussQuadrature()
73837045ce4SJed Brown @*/
73937045ce4SJed Brown PetscErrorCode PetscDTLegendreEval(PetscInt npoints,const PetscReal *points,PetscInt ndegree,const PetscInt *degrees,PetscReal *B,PetscReal *D,PetscReal *D2)
74037045ce4SJed Brown {
741*94e21283SToby Isaac   PetscErrorCode ierr;
74237045ce4SJed Brown 
74337045ce4SJed Brown   PetscFunctionBegin;
744*94e21283SToby Isaac   ierr = PetscDTJacobiEval(npoints, 0., 0., points, ndegree, degrees, B, D, D2);CHKERRQ(ierr);
74537045ce4SJed Brown   PetscFunctionReturn(0);
74637045ce4SJed Brown }
74737045ce4SJed Brown 
748e6a796c3SToby Isaac /* solve the symmetric tridiagonal eigenvalue system, writing the eigenvalues into eigs and the eigenvectors into V
749e6a796c3SToby Isaac  * with lds n; diag and subdiag are overwritten */
750e6a796c3SToby Isaac static PetscErrorCode PetscDTSymmetricTridiagonalEigensolve(PetscInt n, PetscReal diag[], PetscReal subdiag[],
751e6a796c3SToby Isaac                                                             PetscReal eigs[], PetscScalar V[])
752e6a796c3SToby Isaac {
753e6a796c3SToby Isaac   char jobz = 'V'; /* eigenvalues and eigenvectors */
754e6a796c3SToby Isaac   char range = 'A'; /* all eigenvalues will be found */
755e6a796c3SToby Isaac   PetscReal VL = 0.; /* ignored because range is 'A' */
756e6a796c3SToby Isaac   PetscReal VU = 0.; /* ignored because range is 'A' */
757e6a796c3SToby Isaac   PetscBLASInt IL = 0; /* ignored because range is 'A' */
758e6a796c3SToby Isaac   PetscBLASInt IU = 0; /* ignored because range is 'A' */
759e6a796c3SToby Isaac   PetscReal abstol = 0.; /* unused */
760e6a796c3SToby Isaac   PetscBLASInt bn, bm, ldz; /* bm will equal bn on exit */
761e6a796c3SToby Isaac   PetscBLASInt *isuppz;
762e6a796c3SToby Isaac   PetscBLASInt lwork, liwork;
763e6a796c3SToby Isaac   PetscReal workquery;
764e6a796c3SToby Isaac   PetscBLASInt  iworkquery;
765e6a796c3SToby Isaac   PetscBLASInt *iwork;
766e6a796c3SToby Isaac   PetscBLASInt info;
767e6a796c3SToby Isaac   PetscReal *work = NULL;
768e6a796c3SToby Isaac   PetscErrorCode ierr;
769e6a796c3SToby Isaac 
770e6a796c3SToby Isaac   PetscFunctionBegin;
771e6a796c3SToby Isaac #if !defined(PETSCDTGAUSSIANQUADRATURE_EIG)
772e6a796c3SToby Isaac   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "A LAPACK symmetric tridiagonal eigensolver could not be found");
773e6a796c3SToby Isaac #endif
774e6a796c3SToby Isaac   ierr = PetscBLASIntCast(n, &bn);CHKERRQ(ierr);
775e6a796c3SToby Isaac   ierr = PetscBLASIntCast(n, &ldz);CHKERRQ(ierr);
776e6a796c3SToby Isaac #if !defined(PETSC_MISSING_LAPACK_STEGR)
777e6a796c3SToby Isaac   ierr = PetscMalloc1(2 * n, &isuppz);CHKERRQ(ierr);
778e6a796c3SToby Isaac   lwork = -1;
779e6a796c3SToby Isaac   liwork = -1;
780e6a796c3SToby Isaac   PetscStackCallBLAS("LAPACKstegr",LAPACKstegr_(&jobz,&range,&bn,diag,subdiag,&VL,&VU,&IL,&IU,&abstol,&bm,eigs,V,&ldz,isuppz,&workquery,&lwork,&iworkquery,&liwork,&info));
781e6a796c3SToby Isaac   if (info) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"xSTEGR error");
782e6a796c3SToby Isaac   lwork = (PetscBLASInt) workquery;
783e6a796c3SToby Isaac   liwork = (PetscBLASInt) iworkquery;
784e6a796c3SToby Isaac   ierr = PetscMalloc2(lwork, &work, liwork, &iwork);CHKERRQ(ierr);
785e6a796c3SToby Isaac   ierr = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr);
786e6a796c3SToby Isaac   PetscStackCallBLAS("LAPACKstegr",LAPACKstegr_(&jobz,&range,&bn,diag,subdiag,&VL,&VU,&IL,&IU,&abstol,&bm,eigs,V,&ldz,isuppz,work,&lwork,iwork,&liwork,&info));
787e6a796c3SToby Isaac   ierr = PetscFPTrapPop();CHKERRQ(ierr);
788e6a796c3SToby Isaac   if (info) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"xSTEGR error");
789e6a796c3SToby Isaac   ierr = PetscFree2(work, iwork);CHKERRQ(ierr);
790e6a796c3SToby Isaac   ierr = PetscFree(isuppz);CHKERRQ(ierr);
791e6a796c3SToby Isaac #elif !defined(PETSC_MISSING_LAPACK_STEQR)
792e6a796c3SToby Isaac   jobz = 'I'; /* Compute eigenvalues and eigenvectors of the
793e6a796c3SToby Isaac                  tridiagonal matrix.  Z is initialized to the identity
794e6a796c3SToby Isaac                  matrix. */
795e6a796c3SToby Isaac   ierr = PetscMalloc1(PetscMax(1,2*n-2),&work);CHKERRQ(ierr);
796e6a796c3SToby Isaac   PetscStackCallBLAS("LAPACKsteqr",LAPACKsteqr_("I",&bn,diag,subdiag,V,&ldz,work,&info));
797e6a796c3SToby Isaac   ierr = PetscFPTrapPop();CHKERRQ(ierr);
798e6a796c3SToby Isaac   if (info) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"xSTEQR error");
799e6a796c3SToby Isaac   ierr = PetscFree(work);CHKERRQ(ierr);
800e6a796c3SToby Isaac   ierr = PetscArraycpy(eigs,diag,n);CHKERRQ(ierr);
801e6a796c3SToby Isaac #endif
802e6a796c3SToby Isaac   PetscFunctionReturn(0);
803e6a796c3SToby Isaac }
804e6a796c3SToby Isaac 
805e6a796c3SToby Isaac /* Formula for the weights at the endpoints (-1 and 1) of Gauss-Lobatto-Jacobi
806e6a796c3SToby Isaac  * quadrature rules on the interval [-1, 1] */
807e6a796c3SToby Isaac static PetscErrorCode PetscDTGaussLobattoJacobiEndweights_Internal(PetscInt n, PetscReal alpha, PetscReal beta, PetscReal *leftw, PetscReal *rightw)
808e6a796c3SToby Isaac {
809e6a796c3SToby Isaac   PetscReal twoab1;
810e6a796c3SToby Isaac   PetscInt  m = n - 2;
811e6a796c3SToby Isaac   PetscReal a = alpha + 1.;
812e6a796c3SToby Isaac   PetscReal b = beta + 1.;
813e6a796c3SToby Isaac   PetscReal gra, grb;
814e6a796c3SToby Isaac 
815e6a796c3SToby Isaac   PetscFunctionBegin;
816e6a796c3SToby Isaac   twoab1 = PetscPowReal(2., a + b - 1.);
817e6a796c3SToby Isaac #if defined(PETSC_HAVE_LGAMMA)
818e6a796c3SToby Isaac   grb = PetscExpReal(2. * PetscLGamma(b+1.) + PetscLGamma(m+1.) + PetscLGamma(m+a+1.) -
819e6a796c3SToby Isaac                      (PetscLGamma(m+b+1) + PetscLGamma(m+a+b+1.)));
820e6a796c3SToby Isaac   gra = PetscExpReal(2. * PetscLGamma(a+1.) + PetscLGamma(m+1.) + PetscLGamma(m+b+1.) -
821e6a796c3SToby Isaac                      (PetscLGamma(m+a+1) + PetscLGamma(m+a+b+1.)));
822e6a796c3SToby Isaac #else
823e6a796c3SToby Isaac   {
824e6a796c3SToby Isaac     PetscInt alphai = (PetscInt) alpha;
825e6a796c3SToby Isaac     PetscInt betai = (PetscInt) beta;
826*94e21283SToby Isaac     PetscErrorCode ierr;
827e6a796c3SToby Isaac 
828e6a796c3SToby Isaac     if ((PetscReal) alphai == alpha && (PetscReal) betai == beta) {
829e6a796c3SToby Isaac       PetscReal binom1, binom2;
830e6a796c3SToby Isaac 
831e6a796c3SToby Isaac       ierr = PetscDTBinomial(m+b, b, &binom1);CHKERRQ(ierr);
832e6a796c3SToby Isaac       ierr = PetscDTBinomial(m+a+b, b, &binom2);CHKERRQ(ierr);
833e6a796c3SToby Isaac       grb = 1./ (binom1 * binom2);
834e6a796c3SToby Isaac       ierr = PetscDTBinomial(m+a, a, &binom1);CHKERRQ(ierr);
835e6a796c3SToby Isaac       ierr = PetscDTBinomial(m+a+b, a, &binom2);CHKERRQ(ierr);
836e6a796c3SToby Isaac       gra = 1./ (binom1 * binom2);
837e6a796c3SToby Isaac     } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"lgamma() - math routine is unavailable.");
838e6a796c3SToby Isaac   }
839e6a796c3SToby Isaac #endif
840e6a796c3SToby Isaac   *leftw = twoab1 * grb / b;
841e6a796c3SToby Isaac   *rightw = twoab1 * gra / a;
842e6a796c3SToby Isaac   PetscFunctionReturn(0);
843e6a796c3SToby Isaac }
844e6a796c3SToby Isaac 
845e6a796c3SToby Isaac /* Evaluates the nth jacobi polynomial with weight parameters a,b at a point x.
846e6a796c3SToby Isaac    Recurrence relations implemented from the pseudocode given in Karniadakis and Sherwin, Appendix B */
847e6a796c3SToby Isaac PETSC_STATIC_INLINE PetscErrorCode PetscDTComputeJacobi(PetscReal a, PetscReal b, PetscInt n, PetscReal x, PetscReal *P)
848e6a796c3SToby Isaac {
849*94e21283SToby Isaac   PetscReal pn1, pn2;
850*94e21283SToby Isaac   PetscReal cnm1, cnm1x, cnm2;
851e6a796c3SToby Isaac   PetscInt  k;
852e6a796c3SToby Isaac 
853e6a796c3SToby Isaac   PetscFunctionBegin;
854e6a796c3SToby Isaac   if (!n) {*P = 1.0; PetscFunctionReturn(0);}
855*94e21283SToby Isaac   PetscDTJacobiRecurrence_Internal(1,a,b,cnm1,cnm1x,cnm2);
856*94e21283SToby Isaac   pn2 = 1.;
857*94e21283SToby Isaac   pn1 = cnm1 + cnm1x*x;
858*94e21283SToby Isaac   if (n == 1) {*P = pn1; PetscFunctionReturn(0);}
859e6a796c3SToby Isaac   *P  = 0.0;
860e6a796c3SToby Isaac   for (k = 2; k < n+1; ++k) {
861*94e21283SToby Isaac     PetscDTJacobiRecurrence_Internal(k,a,b,cnm1,cnm1x,cnm2);
862e6a796c3SToby Isaac 
863*94e21283SToby Isaac     *P  = (cnm1 + cnm1x*x)*pn1 - cnm2*pn2;
864e6a796c3SToby Isaac     pn2 = pn1;
865e6a796c3SToby Isaac     pn1 = *P;
866e6a796c3SToby Isaac   }
867e6a796c3SToby Isaac   PetscFunctionReturn(0);
868e6a796c3SToby Isaac }
869e6a796c3SToby Isaac 
870e6a796c3SToby Isaac /* Evaluates the first derivative of P_{n}^{a,b} at a point x. */
871e6a796c3SToby Isaac PETSC_STATIC_INLINE PetscErrorCode PetscDTComputeJacobiDerivative(PetscReal a, PetscReal b, PetscInt n, PetscReal x, PetscInt k, PetscReal *P)
872e6a796c3SToby Isaac {
873e6a796c3SToby Isaac   PetscReal      nP;
874e6a796c3SToby Isaac   PetscInt       i;
875e6a796c3SToby Isaac   PetscErrorCode ierr;
876e6a796c3SToby Isaac 
877e6a796c3SToby Isaac   PetscFunctionBegin;
878e6a796c3SToby Isaac   if (k > n) {*P = 0.0; PetscFunctionReturn(0);}
879e6a796c3SToby Isaac   ierr = PetscDTComputeJacobi(a+k, b+k, n-k, x, &nP);CHKERRQ(ierr);
880e6a796c3SToby Isaac   for (i = 0; i < k; i++) nP *= (a + b + n + 1. + i) * 0.5;
881e6a796c3SToby Isaac   *P = nP;
882e6a796c3SToby Isaac   PetscFunctionReturn(0);
883e6a796c3SToby Isaac }
884e6a796c3SToby Isaac 
885e6a796c3SToby Isaac /* Maps from [-1,1]^2 to the (-1,1) reference triangle */
886e6a796c3SToby Isaac PETSC_STATIC_INLINE PetscErrorCode PetscDTMapSquareToTriangle_Internal(PetscReal x, PetscReal y, PetscReal *xi, PetscReal *eta)
887e6a796c3SToby Isaac {
888e6a796c3SToby Isaac   PetscFunctionBegin;
889e6a796c3SToby Isaac   *xi  = 0.5 * (1.0 + x) * (1.0 - y) - 1.0;
890e6a796c3SToby Isaac   *eta = y;
891e6a796c3SToby Isaac   PetscFunctionReturn(0);
892e6a796c3SToby Isaac }
893e6a796c3SToby Isaac 
894e6a796c3SToby Isaac static PetscErrorCode PetscDTGaussJacobiQuadrature_Newton_Internal(PetscInt npoints, PetscReal a, PetscReal b, PetscReal x[], PetscReal w[])
895e6a796c3SToby Isaac {
896e6a796c3SToby Isaac   PetscInt       maxIter = 100;
897*94e21283SToby Isaac   PetscReal      eps     = PetscExpReal(0.75 * PetscLogReal(PETSC_MACHINE_EPSILON));
898*94e21283SToby Isaac   PetscReal      a1, a2, a3, a4, a5, a6, gf;
899e6a796c3SToby Isaac   PetscInt       k;
900e6a796c3SToby Isaac   PetscErrorCode ierr;
901e6a796c3SToby Isaac 
902e6a796c3SToby Isaac   PetscFunctionBegin;
903e6a796c3SToby Isaac 
904e6a796c3SToby Isaac   a1 = PetscPowReal(2.0, a+b+1);
905*94e21283SToby Isaac #if defined(PETSC_HAVE_LGAMMA)
906*94e21283SToby Isaac   a2 = PetscLGamma(a + npoints + 1);
907*94e21283SToby Isaac   a3 = PetscLGamma(b + npoints + 1);
908*94e21283SToby Isaac   a4 = PetscLGamma(a + b + npoints + 1);
909*94e21283SToby Isaac   a5 = PetscLGamma(npoints + 1);
910*94e21283SToby Isaac   gf = PetscExpReal(a2 + a3 - (a4 + a5));
911e6a796c3SToby Isaac #else
912e6a796c3SToby Isaac   {
913e6a796c3SToby Isaac     PetscInt ia, ib;
914e6a796c3SToby Isaac 
915e6a796c3SToby Isaac     ia = (PetscInt) a;
916e6a796c3SToby Isaac     ib = (PetscInt) b;
917*94e21283SToby Isaac     gf = 1.;
918*94e21283SToby Isaac     if (ia == a && ia >= 0) { /* compute ratio of rising factorals wrt a */
919*94e21283SToby Isaac       for (k = 0; k < ia; k++) gf *= (npoints + 1. + k) / (npoints + b + 1. + k);
920*94e21283SToby Isaac     } else if (b == b && ib >= 0) { /* compute ratio of rising factorials wrt b */
921*94e21283SToby Isaac       for (k = 0; k < ib; k++) gf *= (npoints + 1. + k) / (npoints + a + 1. + k);
922*94e21283SToby Isaac     } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"lgamma() - math routine is unavailable.");
923e6a796c3SToby Isaac   }
924e6a796c3SToby Isaac #endif
925e6a796c3SToby Isaac 
926*94e21283SToby Isaac   a6   = a1 * gf;
927e6a796c3SToby Isaac   /* Computes the m roots of P_{m}^{a,b} on [-1,1] by Newton's method with Chebyshev points as initial guesses.
928e6a796c3SToby Isaac    Algorithm implemented from the pseudocode given by Karniadakis and Sherwin and Python in FIAT */
929e6a796c3SToby Isaac   for (k = 0; k < npoints; ++k) {
930*94e21283SToby Isaac     PetscReal r = PetscCosReal(PETSC_PI * (1. - (4.*k + 3. + 2.*b) / (4.*npoints + 2.*(a + b + 1.)))), dP;
931e6a796c3SToby Isaac     PetscInt  j;
932e6a796c3SToby Isaac 
933e6a796c3SToby Isaac     if (k > 0) r = 0.5 * (r + x[k-1]);
934e6a796c3SToby Isaac     for (j = 0; j < maxIter; ++j) {
935e6a796c3SToby Isaac       PetscReal s = 0.0, delta, f, fp;
936e6a796c3SToby Isaac       PetscInt  i;
937e6a796c3SToby Isaac 
938e6a796c3SToby Isaac       for (i = 0; i < k; ++i) s = s + 1.0 / (r - x[i]);
939e6a796c3SToby Isaac       ierr = PetscDTComputeJacobi(a, b, npoints, r, &f);CHKERRQ(ierr);
940e6a796c3SToby Isaac       ierr = PetscDTComputeJacobiDerivative(a, b, npoints, r, 1, &fp);CHKERRQ(ierr);
941e6a796c3SToby Isaac       delta = f / (fp - f * s);
942e6a796c3SToby Isaac       r     = r - delta;
943e6a796c3SToby Isaac       if (PetscAbsReal(delta) < eps) break;
944e6a796c3SToby Isaac     }
945e6a796c3SToby Isaac     x[k] = r;
946e6a796c3SToby Isaac     ierr = PetscDTComputeJacobiDerivative(a, b, npoints, x[k], 1, &dP);CHKERRQ(ierr);
947e6a796c3SToby Isaac     w[k] = a6 / (1.0 - PetscSqr(x[k])) / PetscSqr(dP);
948e6a796c3SToby Isaac   }
949e6a796c3SToby Isaac   PetscFunctionReturn(0);
950e6a796c3SToby Isaac }
951e6a796c3SToby Isaac 
952*94e21283SToby Isaac /* Compute the diagonals of the Jacobi matrix used in Golub & Welsch algorithms for Gauss-Jacobi
953e6a796c3SToby Isaac  * quadrature weight calculations on [-1,1] for exponents (1. + x)^a (1.-x)^b */
954e6a796c3SToby Isaac static PetscErrorCode PetscDTJacobiMatrix_Internal(PetscInt nPoints, PetscReal a, PetscReal b, PetscReal *d, PetscReal *s)
955e6a796c3SToby Isaac {
956e6a796c3SToby Isaac   PetscInt       i;
957e6a796c3SToby Isaac 
958e6a796c3SToby Isaac   PetscFunctionBegin;
959e6a796c3SToby Isaac   for (i = 0; i < nPoints; i++) {
960*94e21283SToby Isaac     PetscReal A, B, C;
961e6a796c3SToby Isaac 
962*94e21283SToby Isaac     PetscDTJacobiRecurrence_Internal(i+1,a,b,A,B,C);
963*94e21283SToby Isaac     d[i] = -A / B;
964*94e21283SToby Isaac     if (i) s[i-1] *= C / B;
965*94e21283SToby Isaac     if (i < nPoints - 1) s[i] = 1. / B;
966e6a796c3SToby Isaac   }
967e6a796c3SToby Isaac   PetscFunctionReturn(0);
968e6a796c3SToby Isaac }
969e6a796c3SToby Isaac 
970e6a796c3SToby Isaac static PetscErrorCode PetscDTGaussJacobiQuadrature_GolubWelsch_Internal(PetscInt npoints, PetscReal a, PetscReal b, PetscReal *x, PetscReal *w)
971e6a796c3SToby Isaac {
972e6a796c3SToby Isaac   PetscReal mu0;
973e6a796c3SToby Isaac   PetscReal ga, gb, gab;
974e6a796c3SToby Isaac   PetscInt i;
975e6a796c3SToby Isaac   PetscErrorCode ierr;
976e6a796c3SToby Isaac 
977e6a796c3SToby Isaac   PetscFunctionBegin;
978e6a796c3SToby Isaac   ierr = PetscCitationsRegister(GolubWelschCitation, &GolubWelschCite);CHKERRQ(ierr);
979e6a796c3SToby Isaac 
980e6a796c3SToby Isaac #if defined(PETSC_HAVE_TGAMMA)
981e6a796c3SToby Isaac   ga  = PetscTGamma(a + 1);
982e6a796c3SToby Isaac   gb  = PetscTGamma(b + 1);
983e6a796c3SToby Isaac   gab = PetscTGamma(a + b + 2);
984e6a796c3SToby Isaac #else
985e6a796c3SToby Isaac   {
986e6a796c3SToby Isaac     PetscInt ia, ib;
987e6a796c3SToby Isaac 
988e6a796c3SToby Isaac     ia = (PetscInt) a;
989e6a796c3SToby Isaac     ib = (PetscInt) b;
990e6a796c3SToby Isaac     if (ia == a && ib == b && ia + 1 > 0 && ib + 1 > 0 && ia + ib + 2 > 0) { /* All gamma(x) terms are (x-1)! terms */
991e6a796c3SToby Isaac       ierr = PetscDTFactorial(ia, &ga);CHKERRQ(ierr);
992e6a796c3SToby Isaac       ierr = PetscDTFactorial(ib, &gb);CHKERRQ(ierr);
993e6a796c3SToby Isaac       ierr = PetscDTFactorial(ia + ib + 1, &gb);CHKERRQ(ierr);
994e6a796c3SToby Isaac     } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"tgamma() - math routine is unavailable.");
995e6a796c3SToby Isaac   }
996e6a796c3SToby Isaac #endif
997e6a796c3SToby Isaac   mu0 = PetscPowReal(2.,a + b + 1.) * ga * gb / gab;
998e6a796c3SToby Isaac 
999e6a796c3SToby Isaac #if defined(PETSCDTGAUSSIANQUADRATURE_EIG)
1000e6a796c3SToby Isaac   {
1001e6a796c3SToby Isaac     PetscReal *diag, *subdiag;
1002e6a796c3SToby Isaac     PetscScalar *V;
1003e6a796c3SToby Isaac 
1004e6a796c3SToby Isaac     ierr = PetscMalloc2(npoints, &diag, npoints, &subdiag);CHKERRQ(ierr);
1005e6a796c3SToby Isaac     ierr = PetscMalloc1(npoints*npoints, &V);CHKERRQ(ierr);
1006e6a796c3SToby Isaac     ierr = PetscDTJacobiMatrix_Internal(npoints, a, b, diag, subdiag);CHKERRQ(ierr);
1007e6a796c3SToby Isaac     for (i = 0; i < npoints - 1; i++) subdiag[i] = PetscSqrtReal(subdiag[i]);
1008e6a796c3SToby Isaac     ierr = PetscDTSymmetricTridiagonalEigensolve(npoints, diag, subdiag, x, V);CHKERRQ(ierr);
1009*94e21283SToby Isaac     for (i = 0; i < npoints; i++) w[i] = PetscSqr(PetscRealPart(V[i * npoints])) * mu0;
1010e6a796c3SToby Isaac     ierr = PetscFree(V);CHKERRQ(ierr);
1011e6a796c3SToby Isaac     ierr = PetscFree2(diag, subdiag);CHKERRQ(ierr);
1012e6a796c3SToby Isaac   }
1013e6a796c3SToby Isaac #else
1014e6a796c3SToby Isaac   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "A LAPACK symmetric tridiagonal eigensolver could not be found");
1015e6a796c3SToby Isaac #endif
1016*94e21283SToby Isaac   { /* As of March 2, 2020, The Sun Performance Library breaks the LAPACK contract for xstegr and xsteqr: the
1017*94e21283SToby Isaac        eigenvalues are not guaranteed to be in ascending order.  So we heave a passive aggressive sigh and check that
1018*94e21283SToby Isaac        the eigenvalues are sorted */
1019*94e21283SToby Isaac     PetscBool sorted;
1020*94e21283SToby Isaac 
1021*94e21283SToby Isaac     ierr = PetscSortedReal(npoints, x, &sorted);CHKERRQ(ierr);
1022*94e21283SToby Isaac     if (!sorted) {
1023*94e21283SToby Isaac       PetscInt *order, i;
1024*94e21283SToby Isaac       PetscReal *tmp;
1025*94e21283SToby Isaac 
1026*94e21283SToby Isaac       ierr = PetscMalloc2(npoints, &order, npoints, &tmp);CHKERRQ(ierr);
1027*94e21283SToby Isaac       for (i = 0; i < npoints; i++) order[i] = i;
1028*94e21283SToby Isaac       ierr = PetscSortRealWithPermutation(npoints, x, order);CHKERRQ(ierr);
1029*94e21283SToby Isaac       ierr = PetscArraycpy(tmp, x, npoints);CHKERRQ(ierr);
1030*94e21283SToby Isaac       for (i = 0; i < npoints; i++) x[i] = tmp[order[i]];
1031*94e21283SToby Isaac       ierr = PetscArraycpy(tmp, w, npoints);CHKERRQ(ierr);
1032*94e21283SToby Isaac       for (i = 0; i < npoints; i++) w[i] = tmp[order[i]];
1033*94e21283SToby Isaac       ierr = PetscFree2(order, tmp);CHKERRQ(ierr);
1034*94e21283SToby Isaac     }
1035*94e21283SToby Isaac   }
1036e6a796c3SToby Isaac   PetscFunctionReturn(0);
1037e6a796c3SToby Isaac }
1038e6a796c3SToby Isaac 
1039e6a796c3SToby Isaac static PetscErrorCode PetscDTGaussJacobiQuadrature_Internal(PetscInt npoints,PetscReal alpha, PetscReal beta, PetscReal x[], PetscReal w[], PetscBool newton)
1040e6a796c3SToby Isaac {
1041e6a796c3SToby Isaac   PetscErrorCode ierr;
1042e6a796c3SToby Isaac 
1043e6a796c3SToby Isaac   PetscFunctionBegin;
1044e6a796c3SToby Isaac   if (npoints < 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Number of points must be positive");
1045e6a796c3SToby Isaac   /* If asking for a 1D Lobatto point, just return the non-Lobatto 1D point */
1046e6a796c3SToby Isaac   if (alpha <= -1.) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"alpha must be > -1.");
1047e6a796c3SToby Isaac   if (beta <= -1.) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"beta must be > -1.");
1048e6a796c3SToby Isaac 
1049e6a796c3SToby Isaac   if (newton) {
1050e6a796c3SToby Isaac     ierr = PetscDTGaussJacobiQuadrature_Newton_Internal(npoints, alpha, beta, x, w);CHKERRQ(ierr);
1051e6a796c3SToby Isaac   } else {
1052e6a796c3SToby Isaac     ierr = PetscDTGaussJacobiQuadrature_GolubWelsch_Internal(npoints, alpha, beta, x, w);CHKERRQ(ierr);
1053e6a796c3SToby Isaac   }
1054e6a796c3SToby Isaac   if (alpha == beta) { /* symmetrize */
1055e6a796c3SToby Isaac     PetscInt i;
1056e6a796c3SToby Isaac     for (i = 0; i < (npoints + 1) / 2; i++) {
1057e6a796c3SToby Isaac       PetscInt  j  = npoints - 1 - i;
1058e6a796c3SToby Isaac       PetscReal xi = x[i];
1059e6a796c3SToby Isaac       PetscReal xj = x[j];
1060e6a796c3SToby Isaac       PetscReal wi = w[i];
1061e6a796c3SToby Isaac       PetscReal wj = w[j];
1062e6a796c3SToby Isaac 
1063e6a796c3SToby Isaac       x[i] = (xi - xj) / 2.;
1064e6a796c3SToby Isaac       x[j] = (xj - xi) / 2.;
1065e6a796c3SToby Isaac       w[i] = w[j] = (wi + wj) / 2.;
1066e6a796c3SToby Isaac     }
1067e6a796c3SToby Isaac   }
1068e6a796c3SToby Isaac   PetscFunctionReturn(0);
1069e6a796c3SToby Isaac }
1070e6a796c3SToby Isaac 
1071*94e21283SToby Isaac /*@
1072*94e21283SToby Isaac   PetscDTGaussJacobiQuadrature - quadrature for the interval [a, b] with the weight function
1073*94e21283SToby Isaac   $(x-a)^\alpha (x-b)^\beta$.
1074*94e21283SToby Isaac 
1075*94e21283SToby Isaac   Not collective
1076*94e21283SToby Isaac 
1077*94e21283SToby Isaac   Input Parameters:
1078*94e21283SToby Isaac + npoints - the number of points in the quadrature rule
1079*94e21283SToby Isaac . a - the left endpoint of the interval
1080*94e21283SToby Isaac . b - the right endpoint of the interval
1081*94e21283SToby Isaac . alpha - the left exponent
1082*94e21283SToby Isaac - beta - the right exponent
1083*94e21283SToby Isaac 
1084*94e21283SToby Isaac   Output Parameters:
1085*94e21283SToby Isaac + x - array of length npoints, the locations of the quadrature points
1086*94e21283SToby Isaac - w - array of length npoints, the weights of the quadrature points
1087*94e21283SToby Isaac 
1088*94e21283SToby Isaac   Level: intermediate
1089*94e21283SToby Isaac 
1090*94e21283SToby Isaac   Note: this quadrature rule is exact for polynomials up to degree 2*npoints - 1.
1091*94e21283SToby Isaac @*/
1092*94e21283SToby Isaac PetscErrorCode PetscDTGaussJacobiQuadrature(PetscInt npoints,PetscReal a, PetscReal b, PetscReal alpha, PetscReal beta, PetscReal x[], PetscReal w[])
1093e6a796c3SToby Isaac {
1094*94e21283SToby Isaac   PetscInt       i;
1095e6a796c3SToby Isaac   PetscErrorCode ierr;
1096e6a796c3SToby Isaac 
1097e6a796c3SToby Isaac   PetscFunctionBegin;
1098*94e21283SToby Isaac   ierr = PetscDTGaussJacobiQuadrature_Internal(npoints, alpha, beta, x, w, PetscDTGaussQuadratureNewton_Internal);CHKERRQ(ierr);
1099*94e21283SToby Isaac   if (a != -1. || b != 1.) { /* shift */
1100*94e21283SToby Isaac     for (i = 0; i < npoints; i++) {
1101*94e21283SToby Isaac       x[i] = (x[i] + 1.) * ((b - a) / 2.) + a;
1102*94e21283SToby Isaac       w[i] *= (b - a) / 2.;
1103*94e21283SToby Isaac     }
1104*94e21283SToby Isaac   }
1105e6a796c3SToby Isaac   PetscFunctionReturn(0);
1106e6a796c3SToby Isaac }
1107e6a796c3SToby Isaac 
1108e6a796c3SToby Isaac static PetscErrorCode PetscDTGaussLobattoJacobiQuadrature_Internal(PetscInt npoints,PetscReal alpha, PetscReal beta, PetscReal x[], PetscReal w[], PetscBool newton)
1109e6a796c3SToby Isaac {
1110e6a796c3SToby Isaac   PetscInt       i;
1111e6a796c3SToby Isaac   PetscErrorCode ierr;
1112e6a796c3SToby Isaac 
1113e6a796c3SToby Isaac   PetscFunctionBegin;
1114e6a796c3SToby Isaac   if (npoints < 2) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Number of points must be positive");
1115e6a796c3SToby Isaac   /* If asking for a 1D Lobatto point, just return the non-Lobatto 1D point */
1116e6a796c3SToby Isaac   if (alpha <= -1.) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"alpha must be > -1.");
1117e6a796c3SToby Isaac   if (beta <= -1.) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"beta must be > -1.");
1118e6a796c3SToby Isaac 
1119e6a796c3SToby Isaac   x[0] = -1.;
1120e6a796c3SToby Isaac   x[npoints-1] = 1.;
1121*94e21283SToby Isaac   if (npoints > 2) {
1122*94e21283SToby Isaac     ierr = PetscDTGaussJacobiQuadrature_Internal(npoints-2, alpha+1., beta+1., &x[1], &w[1], newton);CHKERRQ(ierr);
1123*94e21283SToby Isaac   }
1124e6a796c3SToby Isaac   for (i = 1; i < npoints - 1; i++) {
1125e6a796c3SToby Isaac     w[i] /= (1. - x[i]*x[i]);
1126e6a796c3SToby Isaac   }
1127e6a796c3SToby Isaac   ierr = PetscDTGaussLobattoJacobiEndweights_Internal(npoints, alpha, beta, &w[0], &w[npoints-1]);CHKERRQ(ierr);
1128e6a796c3SToby Isaac   PetscFunctionReturn(0);
1129e6a796c3SToby Isaac }
1130e6a796c3SToby Isaac 
113137045ce4SJed Brown /*@
1132*94e21283SToby Isaac   PetscDTGaussLobattoJacobiQuadrature - quadrature for the interval [a, b] with the weight function
1133*94e21283SToby Isaac   $(x-a)^\alpha (x-b)^\beta$, with endpoints a and b included as quadrature points.
1134*94e21283SToby Isaac 
1135*94e21283SToby Isaac   Not collective
1136*94e21283SToby Isaac 
1137*94e21283SToby Isaac   Input Parameters:
1138*94e21283SToby Isaac + npoints - the number of points in the quadrature rule
1139*94e21283SToby Isaac . a - the left endpoint of the interval
1140*94e21283SToby Isaac . b - the right endpoint of the interval
1141*94e21283SToby Isaac . alpha - the left exponent
1142*94e21283SToby Isaac - beta - the right exponent
1143*94e21283SToby Isaac 
1144*94e21283SToby Isaac   Output Parameters:
1145*94e21283SToby Isaac + x - array of length npoints, the locations of the quadrature points
1146*94e21283SToby Isaac - w - array of length npoints, the weights of the quadrature points
1147*94e21283SToby Isaac 
1148*94e21283SToby Isaac   Level: intermediate
1149*94e21283SToby Isaac 
1150*94e21283SToby Isaac   Note: this quadrature rule is exact for polynomials up to degree 2*npoints - 3.
1151*94e21283SToby Isaac @*/
1152*94e21283SToby Isaac PetscErrorCode PetscDTGaussLobattoJacobiQuadrature(PetscInt npoints,PetscReal a, PetscReal b, PetscReal alpha, PetscReal beta, PetscReal x[], PetscReal w[])
1153*94e21283SToby Isaac {
1154*94e21283SToby Isaac   PetscInt       i;
1155*94e21283SToby Isaac   PetscErrorCode ierr;
1156*94e21283SToby Isaac 
1157*94e21283SToby Isaac   PetscFunctionBegin;
1158*94e21283SToby Isaac   ierr = PetscDTGaussLobattoJacobiQuadrature_Internal(npoints, alpha, beta, x, w, PetscDTGaussQuadratureNewton_Internal);CHKERRQ(ierr);
1159*94e21283SToby Isaac   if (a != -1. || b != 1.) { /* shift */
1160*94e21283SToby Isaac     for (i = 0; i < npoints; i++) {
1161*94e21283SToby Isaac       x[i] = (x[i] + 1.) * ((b - a) / 2.) + a;
1162*94e21283SToby Isaac       w[i] *= (b - a) / 2.;
1163*94e21283SToby Isaac     }
1164*94e21283SToby Isaac   }
1165*94e21283SToby Isaac   PetscFunctionReturn(0);
1166*94e21283SToby Isaac }
1167*94e21283SToby Isaac 
1168*94e21283SToby Isaac /*@
1169e6a796c3SToby Isaac    PetscDTGaussQuadrature - create Gauss-Legendre quadrature
117037045ce4SJed Brown 
117137045ce4SJed Brown    Not Collective
117237045ce4SJed Brown 
117337045ce4SJed Brown    Input Arguments:
117437045ce4SJed Brown +  npoints - number of points
117537045ce4SJed Brown .  a - left end of interval (often-1)
117637045ce4SJed Brown -  b - right end of interval (often +1)
117737045ce4SJed Brown 
117837045ce4SJed Brown    Output Arguments:
117937045ce4SJed Brown +  x - quadrature points
118037045ce4SJed Brown -  w - quadrature weights
118137045ce4SJed Brown 
118237045ce4SJed Brown    Level: intermediate
118337045ce4SJed Brown 
118437045ce4SJed Brown    References:
118596a0c994SBarry Smith .   1. - Golub and Welsch, Calculation of Quadrature Rules, Math. Comp. 23(106), 1969.
118637045ce4SJed Brown 
118737045ce4SJed Brown .seealso: PetscDTLegendreEval()
118837045ce4SJed Brown @*/
118937045ce4SJed Brown PetscErrorCode PetscDTGaussQuadrature(PetscInt npoints,PetscReal a,PetscReal b,PetscReal *x,PetscReal *w)
119037045ce4SJed Brown {
119137045ce4SJed Brown   PetscInt       i;
1192e6a796c3SToby Isaac   PetscErrorCode ierr;
119337045ce4SJed Brown 
119437045ce4SJed Brown   PetscFunctionBegin;
1195*94e21283SToby Isaac   ierr = PetscDTGaussJacobiQuadrature_Internal(npoints, 0., 0., x, w, PetscDTGaussQuadratureNewton_Internal);CHKERRQ(ierr);
1196*94e21283SToby Isaac   if (a != -1. || b != 1.) { /* shift */
119737045ce4SJed Brown     for (i = 0; i < npoints; i++) {
1198e6a796c3SToby Isaac       x[i] = (x[i] + 1.) * ((b - a) / 2.) + a;
1199e6a796c3SToby Isaac       w[i] *= (b - a) / 2.;
120037045ce4SJed Brown     }
120137045ce4SJed Brown   }
120237045ce4SJed Brown   PetscFunctionReturn(0);
120337045ce4SJed Brown }
1204194825f6SJed Brown 
12058272889dSSatish Balay /*@C
12068272889dSSatish Balay    PetscDTGaussLobattoLegendreQuadrature - creates a set of the locations and weights of the Gauss-Lobatto-Legendre
12078272889dSSatish Balay                       nodes of a given size on the domain [-1,1]
12088272889dSSatish Balay 
12098272889dSSatish Balay    Not Collective
12108272889dSSatish Balay 
12118272889dSSatish Balay    Input Parameter:
12128272889dSSatish Balay +  n - number of grid nodes
1213f2e8fe4dShannah_mairs -  type - PETSCGAUSSLOBATTOLEGENDRE_VIA_LINEAR_ALGEBRA or PETSCGAUSSLOBATTOLEGENDRE_VIA_NEWTON
12148272889dSSatish Balay 
12158272889dSSatish Balay    Output Arguments:
12168272889dSSatish Balay +  x - quadrature points
12178272889dSSatish Balay -  w - quadrature weights
12188272889dSSatish Balay 
12198272889dSSatish Balay    Notes:
12208272889dSSatish Balay     For n > 30  the Newton approach computes duplicate (incorrect) values for some nodes because the initial guess is apparently not
12218272889dSSatish Balay           close enough to the desired solution
12228272889dSSatish Balay 
12238272889dSSatish Balay    These are useful for implementing spectral methods based on Gauss-Lobatto-Legendre (GLL) nodes
12248272889dSSatish Balay 
1225a8d69d7bSBarry 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
12268272889dSSatish Balay 
12278272889dSSatish Balay    Level: intermediate
12288272889dSSatish Balay 
12298272889dSSatish Balay .seealso: PetscDTGaussQuadrature()
12308272889dSSatish Balay 
12318272889dSSatish Balay @*/
1232916e780bShannah_mairs PetscErrorCode PetscDTGaussLobattoLegendreQuadrature(PetscInt npoints,PetscGaussLobattoLegendreCreateType type,PetscReal *x,PetscReal *w)
12338272889dSSatish Balay {
1234e6a796c3SToby Isaac   PetscBool      newton;
12358272889dSSatish Balay   PetscErrorCode ierr;
12368272889dSSatish Balay 
12378272889dSSatish Balay   PetscFunctionBegin;
12388272889dSSatish Balay   if (npoints < 2) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Must provide at least 2 grid points per element");
1239*94e21283SToby Isaac   newton = (PetscBool) (type == PETSCGAUSSLOBATTOLEGENDRE_VIA_NEWTON);
1240e6a796c3SToby Isaac   ierr = PetscDTGaussLobattoJacobiQuadrature_Internal(npoints, 0., 0., x, w, newton);CHKERRQ(ierr);
12418272889dSSatish Balay   PetscFunctionReturn(0);
12428272889dSSatish Balay }
12438272889dSSatish Balay 
1244744bafbcSMatthew G. Knepley /*@
1245744bafbcSMatthew G. Knepley   PetscDTGaussTensorQuadrature - creates a tensor-product Gauss quadrature
1246744bafbcSMatthew G. Knepley 
1247744bafbcSMatthew G. Knepley   Not Collective
1248744bafbcSMatthew G. Knepley 
1249744bafbcSMatthew G. Knepley   Input Arguments:
1250744bafbcSMatthew G. Knepley + dim     - The spatial dimension
1251a6b92713SMatthew G. Knepley . Nc      - The number of components
1252744bafbcSMatthew G. Knepley . npoints - number of points in one dimension
1253744bafbcSMatthew G. Knepley . a       - left end of interval (often-1)
1254744bafbcSMatthew G. Knepley - b       - right end of interval (often +1)
1255744bafbcSMatthew G. Knepley 
1256744bafbcSMatthew G. Knepley   Output Argument:
1257744bafbcSMatthew G. Knepley . q - A PetscQuadrature object
1258744bafbcSMatthew G. Knepley 
1259744bafbcSMatthew G. Knepley   Level: intermediate
1260744bafbcSMatthew G. Knepley 
1261744bafbcSMatthew G. Knepley .seealso: PetscDTGaussQuadrature(), PetscDTLegendreEval()
1262744bafbcSMatthew G. Knepley @*/
1263a6b92713SMatthew G. Knepley PetscErrorCode PetscDTGaussTensorQuadrature(PetscInt dim, PetscInt Nc, PetscInt npoints, PetscReal a, PetscReal b, PetscQuadrature *q)
1264744bafbcSMatthew G. Knepley {
1265a6b92713SMatthew G. Knepley   PetscInt       totpoints = dim > 1 ? dim > 2 ? npoints*PetscSqr(npoints) : PetscSqr(npoints) : npoints, i, j, k, c;
1266744bafbcSMatthew G. Knepley   PetscReal     *x, *w, *xw, *ww;
1267744bafbcSMatthew G. Knepley   PetscErrorCode ierr;
1268744bafbcSMatthew G. Knepley 
1269744bafbcSMatthew G. Knepley   PetscFunctionBegin;
1270744bafbcSMatthew G. Knepley   ierr = PetscMalloc1(totpoints*dim,&x);CHKERRQ(ierr);
1271a6b92713SMatthew G. Knepley   ierr = PetscMalloc1(totpoints*Nc,&w);CHKERRQ(ierr);
1272744bafbcSMatthew G. Knepley   /* Set up the Golub-Welsch system */
1273744bafbcSMatthew G. Knepley   switch (dim) {
1274744bafbcSMatthew G. Knepley   case 0:
1275744bafbcSMatthew G. Knepley     ierr = PetscFree(x);CHKERRQ(ierr);
1276744bafbcSMatthew G. Knepley     ierr = PetscFree(w);CHKERRQ(ierr);
1277744bafbcSMatthew G. Knepley     ierr = PetscMalloc1(1, &x);CHKERRQ(ierr);
1278a6b92713SMatthew G. Knepley     ierr = PetscMalloc1(Nc, &w);CHKERRQ(ierr);
1279744bafbcSMatthew G. Knepley     x[0] = 0.0;
1280a6b92713SMatthew G. Knepley     for (c = 0; c < Nc; ++c) w[c] = 1.0;
1281744bafbcSMatthew G. Knepley     break;
1282744bafbcSMatthew G. Knepley   case 1:
1283a6b92713SMatthew G. Knepley     ierr = PetscMalloc1(npoints,&ww);CHKERRQ(ierr);
1284a6b92713SMatthew G. Knepley     ierr = PetscDTGaussQuadrature(npoints, a, b, x, ww);CHKERRQ(ierr);
1285a6b92713SMatthew G. Knepley     for (i = 0; i < npoints; ++i) for (c = 0; c < Nc; ++c) w[i*Nc+c] = ww[i];
1286a6b92713SMatthew G. Knepley     ierr = PetscFree(ww);CHKERRQ(ierr);
1287744bafbcSMatthew G. Knepley     break;
1288744bafbcSMatthew G. Knepley   case 2:
1289744bafbcSMatthew G. Knepley     ierr = PetscMalloc2(npoints,&xw,npoints,&ww);CHKERRQ(ierr);
1290744bafbcSMatthew G. Knepley     ierr = PetscDTGaussQuadrature(npoints, a, b, xw, ww);CHKERRQ(ierr);
1291744bafbcSMatthew G. Knepley     for (i = 0; i < npoints; ++i) {
1292744bafbcSMatthew G. Knepley       for (j = 0; j < npoints; ++j) {
1293744bafbcSMatthew G. Knepley         x[(i*npoints+j)*dim+0] = xw[i];
1294744bafbcSMatthew G. Knepley         x[(i*npoints+j)*dim+1] = xw[j];
1295a6b92713SMatthew G. Knepley         for (c = 0; c < Nc; ++c) w[(i*npoints+j)*Nc+c] = ww[i] * ww[j];
1296744bafbcSMatthew G. Knepley       }
1297744bafbcSMatthew G. Knepley     }
1298744bafbcSMatthew G. Knepley     ierr = PetscFree2(xw,ww);CHKERRQ(ierr);
1299744bafbcSMatthew G. Knepley     break;
1300744bafbcSMatthew G. Knepley   case 3:
1301744bafbcSMatthew G. Knepley     ierr = PetscMalloc2(npoints,&xw,npoints,&ww);CHKERRQ(ierr);
1302744bafbcSMatthew G. Knepley     ierr = PetscDTGaussQuadrature(npoints, a, b, xw, ww);CHKERRQ(ierr);
1303744bafbcSMatthew G. Knepley     for (i = 0; i < npoints; ++i) {
1304744bafbcSMatthew G. Knepley       for (j = 0; j < npoints; ++j) {
1305744bafbcSMatthew G. Knepley         for (k = 0; k < npoints; ++k) {
1306744bafbcSMatthew G. Knepley           x[((i*npoints+j)*npoints+k)*dim+0] = xw[i];
1307744bafbcSMatthew G. Knepley           x[((i*npoints+j)*npoints+k)*dim+1] = xw[j];
1308744bafbcSMatthew G. Knepley           x[((i*npoints+j)*npoints+k)*dim+2] = xw[k];
1309a6b92713SMatthew G. Knepley           for (c = 0; c < Nc; ++c) w[((i*npoints+j)*npoints+k)*Nc+c] = ww[i] * ww[j] * ww[k];
1310744bafbcSMatthew G. Knepley         }
1311744bafbcSMatthew G. Knepley       }
1312744bafbcSMatthew G. Knepley     }
1313744bafbcSMatthew G. Knepley     ierr = PetscFree2(xw,ww);CHKERRQ(ierr);
1314744bafbcSMatthew G. Knepley     break;
1315744bafbcSMatthew G. Knepley   default:
1316744bafbcSMatthew G. Knepley     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct quadrature rule for dimension %d", dim);
1317744bafbcSMatthew G. Knepley   }
1318744bafbcSMatthew G. Knepley   ierr = PetscQuadratureCreate(PETSC_COMM_SELF, q);CHKERRQ(ierr);
13192f5fb066SToby Isaac   ierr = PetscQuadratureSetOrder(*q, 2*npoints-1);CHKERRQ(ierr);
1320a6b92713SMatthew G. Knepley   ierr = PetscQuadratureSetData(*q, dim, Nc, totpoints, x, w);CHKERRQ(ierr);
1321d9bac1caSLisandro Dalcin   ierr = PetscObjectChangeTypeName((PetscObject)*q,"GaussTensor");CHKERRQ(ierr);
1322744bafbcSMatthew G. Knepley   PetscFunctionReturn(0);
1323744bafbcSMatthew G. Knepley }
1324744bafbcSMatthew G. Knepley 
1325494e7359SMatthew G. Knepley /* Maps from [-1,1]^2 to the (-1,1) reference triangle */
1326494e7359SMatthew G. Knepley PETSC_STATIC_INLINE PetscErrorCode PetscDTMapCubeToTetrahedron_Internal(PetscReal x, PetscReal y, PetscReal z, PetscReal *xi, PetscReal *eta, PetscReal *zeta)
1327494e7359SMatthew G. Knepley {
1328494e7359SMatthew G. Knepley   PetscFunctionBegin;
1329494e7359SMatthew G. Knepley   *xi   = 0.25 * (1.0 + x) * (1.0 - y) * (1.0 - z) - 1.0;
1330494e7359SMatthew G. Knepley   *eta  = 0.5  * (1.0 + y) * (1.0 - z) - 1.0;
1331494e7359SMatthew G. Knepley   *zeta = z;
1332494e7359SMatthew G. Knepley   PetscFunctionReturn(0);
1333494e7359SMatthew G. Knepley }
1334494e7359SMatthew G. Knepley 
1335494e7359SMatthew G. Knepley 
1336f5f57ec0SBarry Smith /*@
1337e6a796c3SToby Isaac   PetscDTStroudConicalQuadrature - create Stroud conical quadrature for a simplex
1338494e7359SMatthew G. Knepley 
1339494e7359SMatthew G. Knepley   Not Collective
1340494e7359SMatthew G. Knepley 
1341494e7359SMatthew G. Knepley   Input Arguments:
1342494e7359SMatthew G. Knepley + dim     - The simplex dimension
1343a6b92713SMatthew G. Knepley . Nc      - The number of components
1344dcce0ee2SMatthew G. Knepley . npoints - The number of points in one dimension
1345494e7359SMatthew G. Knepley . a       - left end of interval (often-1)
1346494e7359SMatthew G. Knepley - b       - right end of interval (often +1)
1347494e7359SMatthew G. Knepley 
1348744bafbcSMatthew G. Knepley   Output Argument:
1349552aa4f7SMatthew G. Knepley . q - A PetscQuadrature object
1350494e7359SMatthew G. Knepley 
1351494e7359SMatthew G. Knepley   Level: intermediate
1352494e7359SMatthew G. Knepley 
1353494e7359SMatthew G. Knepley   References:
135496a0c994SBarry Smith .  1. - Karniadakis and Sherwin.  FIAT
1355494e7359SMatthew G. Knepley 
1356e6a796c3SToby Isaac   Note: For dim == 1, this is Gauss-Legendre quadrature
1357e6a796c3SToby Isaac 
1358744bafbcSMatthew G. Knepley .seealso: PetscDTGaussTensorQuadrature(), PetscDTGaussQuadrature()
1359494e7359SMatthew G. Knepley @*/
1360e6a796c3SToby Isaac PetscErrorCode PetscDTStroudConicalQuadrature(PetscInt dim, PetscInt Nc, PetscInt npoints, PetscReal a, PetscReal b, PetscQuadrature *q)
1361494e7359SMatthew G. Knepley {
1362dcce0ee2SMatthew G. Knepley   PetscInt       totpoints = dim > 1 ? dim > 2 ? npoints*PetscSqr(npoints) : PetscSqr(npoints) : npoints;
1363494e7359SMatthew G. Knepley   PetscReal     *px, *wx, *py, *wy, *pz, *wz, *x, *w;
1364e6a796c3SToby Isaac   PetscInt       i, j, k, c; PetscErrorCode ierr;
1365494e7359SMatthew G. Knepley 
1366494e7359SMatthew G. Knepley   PetscFunctionBegin;
1367494e7359SMatthew G. Knepley   if ((a != -1.0) || (b != 1.0)) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must use default internal right now");
1368dcce0ee2SMatthew G. Knepley   ierr = PetscMalloc1(totpoints*dim, &x);CHKERRQ(ierr);
1369dcce0ee2SMatthew G. Knepley   ierr = PetscMalloc1(totpoints*Nc, &w);CHKERRQ(ierr);
1370494e7359SMatthew G. Knepley   switch (dim) {
1371707aa5c5SMatthew G. Knepley   case 0:
1372707aa5c5SMatthew G. Knepley     ierr = PetscFree(x);CHKERRQ(ierr);
1373707aa5c5SMatthew G. Knepley     ierr = PetscFree(w);CHKERRQ(ierr);
1374785e854fSJed Brown     ierr = PetscMalloc1(1, &x);CHKERRQ(ierr);
1375a6b92713SMatthew G. Knepley     ierr = PetscMalloc1(Nc, &w);CHKERRQ(ierr);
1376707aa5c5SMatthew G. Knepley     x[0] = 0.0;
1377a6b92713SMatthew G. Knepley     for (c = 0; c < Nc; ++c) w[c] = 1.0;
1378707aa5c5SMatthew G. Knepley     break;
1379494e7359SMatthew G. Knepley   case 1:
1380dcce0ee2SMatthew G. Knepley     ierr = PetscMalloc1(npoints,&wx);CHKERRQ(ierr);
1381*94e21283SToby Isaac     ierr = PetscDTGaussJacobiQuadrature(npoints, -1., 1., 0.0, 0.0, x, wx);CHKERRQ(ierr);
1382dcce0ee2SMatthew G. Knepley     for (i = 0; i < npoints; ++i) for (c = 0; c < Nc; ++c) w[i*Nc+c] = wx[i];
1383a6b92713SMatthew G. Knepley     ierr = PetscFree(wx);CHKERRQ(ierr);
1384494e7359SMatthew G. Knepley     break;
1385494e7359SMatthew G. Knepley   case 2:
1386dcce0ee2SMatthew G. Knepley     ierr = PetscMalloc4(npoints,&px,npoints,&wx,npoints,&py,npoints,&wy);CHKERRQ(ierr);
1387*94e21283SToby Isaac     ierr = PetscDTGaussJacobiQuadrature(npoints, -1., 1., 0.0, 0.0, px, wx);CHKERRQ(ierr);
1388*94e21283SToby Isaac     ierr = PetscDTGaussJacobiQuadrature(npoints, -1., 1., 1.0, 0.0, py, wy);CHKERRQ(ierr);
1389dcce0ee2SMatthew G. Knepley     for (i = 0; i < npoints; ++i) {
1390dcce0ee2SMatthew G. Knepley       for (j = 0; j < npoints; ++j) {
1391dcce0ee2SMatthew G. Knepley         ierr = PetscDTMapSquareToTriangle_Internal(px[i], py[j], &x[(i*npoints+j)*2+0], &x[(i*npoints+j)*2+1]);CHKERRQ(ierr);
1392dcce0ee2SMatthew G. Knepley         for (c = 0; c < Nc; ++c) w[(i*npoints+j)*Nc+c] = 0.5 * wx[i] * wy[j];
1393494e7359SMatthew G. Knepley       }
1394494e7359SMatthew G. Knepley     }
1395494e7359SMatthew G. Knepley     ierr = PetscFree4(px,wx,py,wy);CHKERRQ(ierr);
1396494e7359SMatthew G. Knepley     break;
1397494e7359SMatthew G. Knepley   case 3:
1398dcce0ee2SMatthew G. Knepley     ierr = PetscMalloc6(npoints,&px,npoints,&wx,npoints,&py,npoints,&wy,npoints,&pz,npoints,&wz);CHKERRQ(ierr);
1399*94e21283SToby Isaac     ierr = PetscDTGaussJacobiQuadrature(npoints, -1., 1., 0.0, 0.0, px, wx);CHKERRQ(ierr);
1400*94e21283SToby Isaac     ierr = PetscDTGaussJacobiQuadrature(npoints, -1., 1., 1.0, 0.0, py, wy);CHKERRQ(ierr);
1401*94e21283SToby Isaac     ierr = PetscDTGaussJacobiQuadrature(npoints, -1., 1., 2.0, 0.0, pz, wz);CHKERRQ(ierr);
1402dcce0ee2SMatthew G. Knepley     for (i = 0; i < npoints; ++i) {
1403dcce0ee2SMatthew G. Knepley       for (j = 0; j < npoints; ++j) {
1404dcce0ee2SMatthew G. Knepley         for (k = 0; k < npoints; ++k) {
1405dcce0ee2SMatthew G. Knepley           ierr = PetscDTMapCubeToTetrahedron_Internal(px[i], py[j], pz[k], &x[((i*npoints+j)*npoints+k)*3+0], &x[((i*npoints+j)*npoints+k)*3+1], &x[((i*npoints+j)*npoints+k)*3+2]);CHKERRQ(ierr);
1406dcce0ee2SMatthew G. Knepley           for (c = 0; c < Nc; ++c) w[((i*npoints+j)*npoints+k)*Nc+c] = 0.125 * wx[i] * wy[j] * wz[k];
1407494e7359SMatthew G. Knepley         }
1408494e7359SMatthew G. Knepley       }
1409494e7359SMatthew G. Knepley     }
1410494e7359SMatthew G. Knepley     ierr = PetscFree6(px,wx,py,wy,pz,wz);CHKERRQ(ierr);
1411494e7359SMatthew G. Knepley     break;
1412494e7359SMatthew G. Knepley   default:
1413494e7359SMatthew G. Knepley     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct quadrature rule for dimension %d", dim);
1414494e7359SMatthew G. Knepley   }
141521454ff5SMatthew G. Knepley   ierr = PetscQuadratureCreate(PETSC_COMM_SELF, q);CHKERRQ(ierr);
14162f5fb066SToby Isaac   ierr = PetscQuadratureSetOrder(*q, 2*npoints-1);CHKERRQ(ierr);
1417dcce0ee2SMatthew G. Knepley   ierr = PetscQuadratureSetData(*q, dim, Nc, totpoints, x, w);CHKERRQ(ierr);
1418d9bac1caSLisandro Dalcin   ierr = PetscObjectChangeTypeName((PetscObject)*q,"GaussJacobi");CHKERRQ(ierr);
1419494e7359SMatthew G. Knepley   PetscFunctionReturn(0);
1420494e7359SMatthew G. Knepley }
1421494e7359SMatthew G. Knepley 
1422f5f57ec0SBarry Smith /*@
1423b3c0f97bSTom Klotz   PetscDTTanhSinhTensorQuadrature - create tanh-sinh quadrature for a tensor product cell
1424b3c0f97bSTom Klotz 
1425b3c0f97bSTom Klotz   Not Collective
1426b3c0f97bSTom Klotz 
1427b3c0f97bSTom Klotz   Input Arguments:
1428b3c0f97bSTom Klotz + dim   - The cell dimension
1429b3c0f97bSTom Klotz . level - The number of points in one dimension, 2^l
1430b3c0f97bSTom Klotz . a     - left end of interval (often-1)
1431b3c0f97bSTom Klotz - b     - right end of interval (often +1)
1432b3c0f97bSTom Klotz 
1433b3c0f97bSTom Klotz   Output Argument:
1434b3c0f97bSTom Klotz . q - A PetscQuadrature object
1435b3c0f97bSTom Klotz 
1436b3c0f97bSTom Klotz   Level: intermediate
1437b3c0f97bSTom Klotz 
1438b3c0f97bSTom Klotz .seealso: PetscDTGaussTensorQuadrature()
1439b3c0f97bSTom Klotz @*/
1440b3c0f97bSTom Klotz PetscErrorCode PetscDTTanhSinhTensorQuadrature(PetscInt dim, PetscInt level, PetscReal a, PetscReal b, PetscQuadrature *q)
1441b3c0f97bSTom Klotz {
1442b3c0f97bSTom Klotz   const PetscInt  p     = 16;                        /* Digits of precision in the evaluation */
1443b3c0f97bSTom Klotz   const PetscReal alpha = (b-a)/2.;                  /* Half-width of the integration interval */
1444b3c0f97bSTom Klotz   const PetscReal beta  = (b+a)/2.;                  /* Center of the integration interval */
1445b3c0f97bSTom Klotz   const PetscReal h     = PetscPowReal(2.0, -level); /* Step size, length between x_k */
1446d84b4d08SMatthew G. Knepley   PetscReal       xk;                                /* Quadrature point x_k on reference domain [-1, 1] */
1447b3c0f97bSTom Klotz   PetscReal       wk    = 0.5*PETSC_PI;              /* Quadrature weight at x_k */
1448b3c0f97bSTom Klotz   PetscReal      *x, *w;
1449b3c0f97bSTom Klotz   PetscInt        K, k, npoints;
1450b3c0f97bSTom Klotz   PetscErrorCode  ierr;
1451b3c0f97bSTom Klotz 
1452b3c0f97bSTom Klotz   PetscFunctionBegin;
1453b3c0f97bSTom Klotz   if (dim > 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Dimension %d not yet implemented", dim);
1454b3c0f97bSTom Klotz   if (!level) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must give a number of significant digits");
1455b3c0f97bSTom Klotz   /* Find K such that the weights are < 32 digits of precision */
1456b3c0f97bSTom Klotz   for (K = 1; PetscAbsReal(PetscLog10Real(wk)) < 2*p; ++K) {
14579add2064SThomas Klotz     wk = 0.5*h*PETSC_PI*PetscCoshReal(K*h)/PetscSqr(PetscCoshReal(0.5*PETSC_PI*PetscSinhReal(K*h)));
1458b3c0f97bSTom Klotz   }
1459b3c0f97bSTom Klotz   ierr = PetscQuadratureCreate(PETSC_COMM_SELF, q);CHKERRQ(ierr);
1460b3c0f97bSTom Klotz   ierr = PetscQuadratureSetOrder(*q, 2*K+1);CHKERRQ(ierr);
1461b3c0f97bSTom Klotz   npoints = 2*K-1;
1462b3c0f97bSTom Klotz   ierr = PetscMalloc1(npoints*dim, &x);CHKERRQ(ierr);
1463b3c0f97bSTom Klotz   ierr = PetscMalloc1(npoints, &w);CHKERRQ(ierr);
1464b3c0f97bSTom Klotz   /* Center term */
1465b3c0f97bSTom Klotz   x[0] = beta;
1466b3c0f97bSTom Klotz   w[0] = 0.5*alpha*PETSC_PI;
1467b3c0f97bSTom Klotz   for (k = 1; k < K; ++k) {
14689add2064SThomas Klotz     wk = 0.5*alpha*h*PETSC_PI*PetscCoshReal(k*h)/PetscSqr(PetscCoshReal(0.5*PETSC_PI*PetscSinhReal(k*h)));
14691118d4bcSLisandro Dalcin     xk = PetscTanhReal(0.5*PETSC_PI*PetscSinhReal(k*h));
1470b3c0f97bSTom Klotz     x[2*k-1] = -alpha*xk+beta;
1471b3c0f97bSTom Klotz     w[2*k-1] = wk;
1472b3c0f97bSTom Klotz     x[2*k+0] =  alpha*xk+beta;
1473b3c0f97bSTom Klotz     w[2*k+0] = wk;
1474b3c0f97bSTom Klotz   }
1475a6b92713SMatthew G. Knepley   ierr = PetscQuadratureSetData(*q, dim, 1, npoints, x, w);CHKERRQ(ierr);
1476b3c0f97bSTom Klotz   PetscFunctionReturn(0);
1477b3c0f97bSTom Klotz }
1478b3c0f97bSTom Klotz 
1479b3c0f97bSTom Klotz PetscErrorCode PetscDTTanhSinhIntegrate(void (*func)(PetscReal, PetscReal *), PetscReal a, PetscReal b, PetscInt digits, PetscReal *sol)
1480b3c0f97bSTom Klotz {
1481b3c0f97bSTom Klotz   const PetscInt  p     = 16;        /* Digits of precision in the evaluation */
1482b3c0f97bSTom Klotz   const PetscReal alpha = (b-a)/2.;  /* Half-width of the integration interval */
1483b3c0f97bSTom Klotz   const PetscReal beta  = (b+a)/2.;  /* Center of the integration interval */
1484b3c0f97bSTom Klotz   PetscReal       h     = 1.0;       /* Step size, length between x_k */
1485b3c0f97bSTom Klotz   PetscInt        l     = 0;         /* Level of refinement, h = 2^{-l} */
1486b3c0f97bSTom Klotz   PetscReal       osum  = 0.0;       /* Integral on last level */
1487b3c0f97bSTom Klotz   PetscReal       psum  = 0.0;       /* Integral on the level before the last level */
1488b3c0f97bSTom Klotz   PetscReal       sum;               /* Integral on current level */
1489446c295cSMatthew G. Knepley   PetscReal       yk;                /* Quadrature point 1 - x_k on reference domain [-1, 1] */
1490b3c0f97bSTom Klotz   PetscReal       lx, rx;            /* Quadrature points to the left and right of 0 on the real domain [a, b] */
1491b3c0f97bSTom Klotz   PetscReal       wk;                /* Quadrature weight at x_k */
1492b3c0f97bSTom Klotz   PetscReal       lval, rval;        /* Terms in the quadature sum to the left and right of 0 */
1493b3c0f97bSTom Klotz   PetscInt        d;                 /* Digits of precision in the integral */
1494b3c0f97bSTom Klotz 
1495b3c0f97bSTom Klotz   PetscFunctionBegin;
1496b3c0f97bSTom Klotz   if (digits <= 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must give a positive number of significant digits");
1497b3c0f97bSTom Klotz   /* Center term */
1498b3c0f97bSTom Klotz   func(beta, &lval);
1499b3c0f97bSTom Klotz   sum = 0.5*alpha*PETSC_PI*lval;
1500b3c0f97bSTom Klotz   /* */
1501b3c0f97bSTom Klotz   do {
1502b3c0f97bSTom Klotz     PetscReal lterm, rterm, maxTerm = 0.0, d1, d2, d3, d4;
1503b3c0f97bSTom Klotz     PetscInt  k = 1;
1504b3c0f97bSTom Klotz 
1505b3c0f97bSTom Klotz     ++l;
1506b3c0f97bSTom Klotz     /* PetscPrintf(PETSC_COMM_SELF, "LEVEL %D sum: %15.15f\n", l, sum); */
1507b3c0f97bSTom Klotz     /* At each level of refinement, h --> h/2 and sum --> sum/2 */
1508b3c0f97bSTom Klotz     psum = osum;
1509b3c0f97bSTom Klotz     osum = sum;
1510b3c0f97bSTom Klotz     h   *= 0.5;
1511b3c0f97bSTom Klotz     sum *= 0.5;
1512b3c0f97bSTom Klotz     do {
15139add2064SThomas Klotz       wk = 0.5*h*PETSC_PI*PetscCoshReal(k*h)/PetscSqr(PetscCoshReal(0.5*PETSC_PI*PetscSinhReal(k*h)));
1514446c295cSMatthew G. Knepley       yk = 1.0/(PetscExpReal(0.5*PETSC_PI*PetscSinhReal(k*h)) * PetscCoshReal(0.5*PETSC_PI*PetscSinhReal(k*h)));
1515446c295cSMatthew G. Knepley       lx = -alpha*(1.0 - yk)+beta;
1516446c295cSMatthew G. Knepley       rx =  alpha*(1.0 - yk)+beta;
1517b3c0f97bSTom Klotz       func(lx, &lval);
1518b3c0f97bSTom Klotz       func(rx, &rval);
1519b3c0f97bSTom Klotz       lterm   = alpha*wk*lval;
1520b3c0f97bSTom Klotz       maxTerm = PetscMax(PetscAbsReal(lterm), maxTerm);
1521b3c0f97bSTom Klotz       sum    += lterm;
1522b3c0f97bSTom Klotz       rterm   = alpha*wk*rval;
1523b3c0f97bSTom Klotz       maxTerm = PetscMax(PetscAbsReal(rterm), maxTerm);
1524b3c0f97bSTom Klotz       sum    += rterm;
1525b3c0f97bSTom Klotz       ++k;
1526b3c0f97bSTom Klotz       /* Only need to evaluate every other point on refined levels */
1527b3c0f97bSTom Klotz       if (l != 1) ++k;
15289add2064SThomas Klotz     } while (PetscAbsReal(PetscLog10Real(wk)) < p); /* Only need to evaluate sum until weights are < 32 digits of precision */
1529b3c0f97bSTom Klotz 
1530b3c0f97bSTom Klotz     d1 = PetscLog10Real(PetscAbsReal(sum - osum));
1531b3c0f97bSTom Klotz     d2 = PetscLog10Real(PetscAbsReal(sum - psum));
1532b3c0f97bSTom Klotz     d3 = PetscLog10Real(maxTerm) - p;
153309d48545SBarry Smith     if (PetscMax(PetscAbsReal(lterm), PetscAbsReal(rterm)) == 0.0) d4 = 0.0;
153409d48545SBarry Smith     else d4 = PetscLog10Real(PetscMax(PetscAbsReal(lterm), PetscAbsReal(rterm)));
1535b3c0f97bSTom Klotz     d  = PetscAbsInt(PetscMin(0, PetscMax(PetscMax(PetscMax(PetscSqr(d1)/d2, 2*d1), d3), d4)));
15369add2064SThomas Klotz   } while (d < digits && l < 12);
1537b3c0f97bSTom Klotz   *sol = sum;
1538e510cb1fSThomas Klotz 
1539b3c0f97bSTom Klotz   PetscFunctionReturn(0);
1540b3c0f97bSTom Klotz }
1541b3c0f97bSTom Klotz 
1542497880caSRichard Tran Mills #if defined(PETSC_HAVE_MPFR)
154329f144ccSMatthew G. Knepley PetscErrorCode PetscDTTanhSinhIntegrateMPFR(void (*func)(PetscReal, PetscReal *), PetscReal a, PetscReal b, PetscInt digits, PetscReal *sol)
154429f144ccSMatthew G. Knepley {
1545e510cb1fSThomas Klotz   const PetscInt  safetyFactor = 2;  /* Calculate abcissa until 2*p digits */
154629f144ccSMatthew G. Knepley   PetscInt        l            = 0;  /* Level of refinement, h = 2^{-l} */
154729f144ccSMatthew G. Knepley   mpfr_t          alpha;             /* Half-width of the integration interval */
154829f144ccSMatthew G. Knepley   mpfr_t          beta;              /* Center of the integration interval */
154929f144ccSMatthew G. Knepley   mpfr_t          h;                 /* Step size, length between x_k */
155029f144ccSMatthew G. Knepley   mpfr_t          osum;              /* Integral on last level */
155129f144ccSMatthew G. Knepley   mpfr_t          psum;              /* Integral on the level before the last level */
155229f144ccSMatthew G. Knepley   mpfr_t          sum;               /* Integral on current level */
155329f144ccSMatthew G. Knepley   mpfr_t          yk;                /* Quadrature point 1 - x_k on reference domain [-1, 1] */
155429f144ccSMatthew G. Knepley   mpfr_t          lx, rx;            /* Quadrature points to the left and right of 0 on the real domain [a, b] */
155529f144ccSMatthew G. Knepley   mpfr_t          wk;                /* Quadrature weight at x_k */
155629f144ccSMatthew G. Knepley   PetscReal       lval, rval;        /* Terms in the quadature sum to the left and right of 0 */
155729f144ccSMatthew G. Knepley   PetscInt        d;                 /* Digits of precision in the integral */
155829f144ccSMatthew G. Knepley   mpfr_t          pi2, kh, msinh, mcosh, maxTerm, curTerm, tmp;
155929f144ccSMatthew G. Knepley 
156029f144ccSMatthew G. Knepley   PetscFunctionBegin;
156129f144ccSMatthew G. Knepley   if (digits <= 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must give a positive number of significant digits");
156229f144ccSMatthew G. Knepley   /* Create high precision storage */
1563c9f744b5SMatthew 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);
156429f144ccSMatthew G. Knepley   /* Initialization */
156529f144ccSMatthew G. Knepley   mpfr_set_d(alpha, 0.5*(b-a), MPFR_RNDN);
156629f144ccSMatthew G. Knepley   mpfr_set_d(beta,  0.5*(b+a), MPFR_RNDN);
156729f144ccSMatthew G. Knepley   mpfr_set_d(osum,  0.0,       MPFR_RNDN);
156829f144ccSMatthew G. Knepley   mpfr_set_d(psum,  0.0,       MPFR_RNDN);
156929f144ccSMatthew G. Knepley   mpfr_set_d(h,     1.0,       MPFR_RNDN);
157029f144ccSMatthew G. Knepley   mpfr_const_pi(pi2, MPFR_RNDN);
157129f144ccSMatthew G. Knepley   mpfr_mul_d(pi2, pi2, 0.5, MPFR_RNDN);
157229f144ccSMatthew G. Knepley   /* Center term */
157329f144ccSMatthew G. Knepley   func(0.5*(b+a), &lval);
157429f144ccSMatthew G. Knepley   mpfr_set(sum, pi2, MPFR_RNDN);
157529f144ccSMatthew G. Knepley   mpfr_mul(sum, sum, alpha, MPFR_RNDN);
157629f144ccSMatthew G. Knepley   mpfr_mul_d(sum, sum, lval, MPFR_RNDN);
157729f144ccSMatthew G. Knepley   /* */
157829f144ccSMatthew G. Knepley   do {
157929f144ccSMatthew G. Knepley     PetscReal d1, d2, d3, d4;
158029f144ccSMatthew G. Knepley     PetscInt  k = 1;
158129f144ccSMatthew G. Knepley 
158229f144ccSMatthew G. Knepley     ++l;
158329f144ccSMatthew G. Knepley     mpfr_set_d(maxTerm, 0.0, MPFR_RNDN);
158429f144ccSMatthew G. Knepley     /* PetscPrintf(PETSC_COMM_SELF, "LEVEL %D sum: %15.15f\n", l, sum); */
158529f144ccSMatthew G. Knepley     /* At each level of refinement, h --> h/2 and sum --> sum/2 */
158629f144ccSMatthew G. Knepley     mpfr_set(psum, osum, MPFR_RNDN);
158729f144ccSMatthew G. Knepley     mpfr_set(osum,  sum, MPFR_RNDN);
158829f144ccSMatthew G. Knepley     mpfr_mul_d(h,   h,   0.5, MPFR_RNDN);
158929f144ccSMatthew G. Knepley     mpfr_mul_d(sum, sum, 0.5, MPFR_RNDN);
159029f144ccSMatthew G. Knepley     do {
159129f144ccSMatthew G. Knepley       mpfr_set_si(kh, k, MPFR_RNDN);
159229f144ccSMatthew G. Knepley       mpfr_mul(kh, kh, h, MPFR_RNDN);
159329f144ccSMatthew G. Knepley       /* Weight */
159429f144ccSMatthew G. Knepley       mpfr_set(wk, h, MPFR_RNDN);
159529f144ccSMatthew G. Knepley       mpfr_sinh_cosh(msinh, mcosh, kh, MPFR_RNDN);
159629f144ccSMatthew G. Knepley       mpfr_mul(msinh, msinh, pi2, MPFR_RNDN);
159729f144ccSMatthew G. Knepley       mpfr_mul(mcosh, mcosh, pi2, MPFR_RNDN);
159829f144ccSMatthew G. Knepley       mpfr_cosh(tmp, msinh, MPFR_RNDN);
159929f144ccSMatthew G. Knepley       mpfr_sqr(tmp, tmp, MPFR_RNDN);
160029f144ccSMatthew G. Knepley       mpfr_mul(wk, wk, mcosh, MPFR_RNDN);
160129f144ccSMatthew G. Knepley       mpfr_div(wk, wk, tmp, MPFR_RNDN);
160229f144ccSMatthew G. Knepley       /* Abscissa */
160329f144ccSMatthew G. Knepley       mpfr_set_d(yk, 1.0, MPFR_RNDZ);
160429f144ccSMatthew G. Knepley       mpfr_cosh(tmp, msinh, MPFR_RNDN);
160529f144ccSMatthew G. Knepley       mpfr_div(yk, yk, tmp, MPFR_RNDZ);
160629f144ccSMatthew G. Knepley       mpfr_exp(tmp, msinh, MPFR_RNDN);
160729f144ccSMatthew G. Knepley       mpfr_div(yk, yk, tmp, MPFR_RNDZ);
160829f144ccSMatthew G. Knepley       /* Quadrature points */
160929f144ccSMatthew G. Knepley       mpfr_sub_d(lx, yk, 1.0, MPFR_RNDZ);
161029f144ccSMatthew G. Knepley       mpfr_mul(lx, lx, alpha, MPFR_RNDU);
161129f144ccSMatthew G. Knepley       mpfr_add(lx, lx, beta, MPFR_RNDU);
161229f144ccSMatthew G. Knepley       mpfr_d_sub(rx, 1.0, yk, MPFR_RNDZ);
161329f144ccSMatthew G. Knepley       mpfr_mul(rx, rx, alpha, MPFR_RNDD);
161429f144ccSMatthew G. Knepley       mpfr_add(rx, rx, beta, MPFR_RNDD);
161529f144ccSMatthew G. Knepley       /* Evaluation */
161629f144ccSMatthew G. Knepley       func(mpfr_get_d(lx, MPFR_RNDU), &lval);
161729f144ccSMatthew G. Knepley       func(mpfr_get_d(rx, MPFR_RNDD), &rval);
161829f144ccSMatthew G. Knepley       /* Update */
161929f144ccSMatthew G. Knepley       mpfr_mul(tmp, wk, alpha, MPFR_RNDN);
162029f144ccSMatthew G. Knepley       mpfr_mul_d(tmp, tmp, lval, MPFR_RNDN);
162129f144ccSMatthew G. Knepley       mpfr_add(sum, sum, tmp, MPFR_RNDN);
162229f144ccSMatthew G. Knepley       mpfr_abs(tmp, tmp, MPFR_RNDN);
162329f144ccSMatthew G. Knepley       mpfr_max(maxTerm, maxTerm, tmp, MPFR_RNDN);
162429f144ccSMatthew G. Knepley       mpfr_set(curTerm, tmp, MPFR_RNDN);
162529f144ccSMatthew G. Knepley       mpfr_mul(tmp, wk, alpha, MPFR_RNDN);
162629f144ccSMatthew G. Knepley       mpfr_mul_d(tmp, tmp, rval, MPFR_RNDN);
162729f144ccSMatthew G. Knepley       mpfr_add(sum, sum, tmp, MPFR_RNDN);
162829f144ccSMatthew G. Knepley       mpfr_abs(tmp, tmp, MPFR_RNDN);
162929f144ccSMatthew G. Knepley       mpfr_max(maxTerm, maxTerm, tmp, MPFR_RNDN);
163029f144ccSMatthew G. Knepley       mpfr_max(curTerm, curTerm, tmp, MPFR_RNDN);
163129f144ccSMatthew G. Knepley       ++k;
163229f144ccSMatthew G. Knepley       /* Only need to evaluate every other point on refined levels */
163329f144ccSMatthew G. Knepley       if (l != 1) ++k;
163429f144ccSMatthew G. Knepley       mpfr_log10(tmp, wk, MPFR_RNDN);
163529f144ccSMatthew G. Knepley       mpfr_abs(tmp, tmp, MPFR_RNDN);
1636c9f744b5SMatthew G. Knepley     } while (mpfr_get_d(tmp, MPFR_RNDN) < safetyFactor*digits); /* Only need to evaluate sum until weights are < 32 digits of precision */
163729f144ccSMatthew G. Knepley     mpfr_sub(tmp, sum, osum, MPFR_RNDN);
163829f144ccSMatthew G. Knepley     mpfr_abs(tmp, tmp, MPFR_RNDN);
163929f144ccSMatthew G. Knepley     mpfr_log10(tmp, tmp, MPFR_RNDN);
164029f144ccSMatthew G. Knepley     d1 = mpfr_get_d(tmp, MPFR_RNDN);
164129f144ccSMatthew G. Knepley     mpfr_sub(tmp, sum, psum, MPFR_RNDN);
164229f144ccSMatthew G. Knepley     mpfr_abs(tmp, tmp, MPFR_RNDN);
164329f144ccSMatthew G. Knepley     mpfr_log10(tmp, tmp, MPFR_RNDN);
164429f144ccSMatthew G. Knepley     d2 = mpfr_get_d(tmp, MPFR_RNDN);
164529f144ccSMatthew G. Knepley     mpfr_log10(tmp, maxTerm, MPFR_RNDN);
1646c9f744b5SMatthew G. Knepley     d3 = mpfr_get_d(tmp, MPFR_RNDN) - digits;
164729f144ccSMatthew G. Knepley     mpfr_log10(tmp, curTerm, MPFR_RNDN);
164829f144ccSMatthew G. Knepley     d4 = mpfr_get_d(tmp, MPFR_RNDN);
164929f144ccSMatthew G. Knepley     d  = PetscAbsInt(PetscMin(0, PetscMax(PetscMax(PetscMax(PetscSqr(d1)/d2, 2*d1), d3), d4)));
1650b0649871SThomas Klotz   } while (d < digits && l < 8);
165129f144ccSMatthew G. Knepley   *sol = mpfr_get_d(sum, MPFR_RNDN);
165229f144ccSMatthew G. Knepley   /* Cleanup */
165329f144ccSMatthew G. Knepley   mpfr_clears(alpha, beta, h, sum, osum, psum, yk, wk, lx, rx, tmp, maxTerm, curTerm, pi2, kh, msinh, mcosh, NULL);
165429f144ccSMatthew G. Knepley   PetscFunctionReturn(0);
165529f144ccSMatthew G. Knepley }
1656d525116cSMatthew G. Knepley #else
1657fbfcfee5SBarry Smith 
1658d525116cSMatthew G. Knepley PetscErrorCode PetscDTTanhSinhIntegrateMPFR(void (*func)(PetscReal, PetscReal *), PetscReal a, PetscReal b, PetscInt digits, PetscReal *sol)
1659d525116cSMatthew G. Knepley {
1660d525116cSMatthew G. Knepley   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "This method will not work without MPFR. Reconfigure using --download-mpfr --download-gmp");
1661d525116cSMatthew G. Knepley }
166229f144ccSMatthew G. Knepley #endif
166329f144ccSMatthew G. Knepley 
1664194825f6SJed Brown /* Overwrites A. Can only handle full-rank problems with m>=n
1665194825f6SJed Brown  * A in column-major format
1666194825f6SJed Brown  * Ainv in row-major format
1667194825f6SJed Brown  * tau has length m
1668194825f6SJed Brown  * worksize must be >= max(1,n)
1669194825f6SJed Brown  */
1670194825f6SJed Brown static PetscErrorCode PetscDTPseudoInverseQR(PetscInt m,PetscInt mstride,PetscInt n,PetscReal *A_in,PetscReal *Ainv_out,PetscScalar *tau,PetscInt worksize,PetscScalar *work)
1671194825f6SJed Brown {
1672194825f6SJed Brown   PetscErrorCode ierr;
1673194825f6SJed Brown   PetscBLASInt   M,N,K,lda,ldb,ldwork,info;
1674194825f6SJed Brown   PetscScalar    *A,*Ainv,*R,*Q,Alpha;
1675194825f6SJed Brown 
1676194825f6SJed Brown   PetscFunctionBegin;
1677194825f6SJed Brown #if defined(PETSC_USE_COMPLEX)
1678194825f6SJed Brown   {
1679194825f6SJed Brown     PetscInt i,j;
1680dcca6d9dSJed Brown     ierr = PetscMalloc2(m*n,&A,m*n,&Ainv);CHKERRQ(ierr);
1681194825f6SJed Brown     for (j=0; j<n; j++) {
1682194825f6SJed Brown       for (i=0; i<m; i++) A[i+m*j] = A_in[i+mstride*j];
1683194825f6SJed Brown     }
1684194825f6SJed Brown     mstride = m;
1685194825f6SJed Brown   }
1686194825f6SJed Brown #else
1687194825f6SJed Brown   A = A_in;
1688194825f6SJed Brown   Ainv = Ainv_out;
1689194825f6SJed Brown #endif
1690194825f6SJed Brown 
1691194825f6SJed Brown   ierr = PetscBLASIntCast(m,&M);CHKERRQ(ierr);
1692194825f6SJed Brown   ierr = PetscBLASIntCast(n,&N);CHKERRQ(ierr);
1693194825f6SJed Brown   ierr = PetscBLASIntCast(mstride,&lda);CHKERRQ(ierr);
1694194825f6SJed Brown   ierr = PetscBLASIntCast(worksize,&ldwork);CHKERRQ(ierr);
1695194825f6SJed Brown   ierr = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr);
1696001a771dSBarry Smith   PetscStackCallBLAS("LAPACKgeqrf",LAPACKgeqrf_(&M,&N,A,&lda,tau,work,&ldwork,&info));
1697194825f6SJed Brown   ierr = PetscFPTrapPop();CHKERRQ(ierr);
1698194825f6SJed Brown   if (info) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"xGEQRF error");
1699194825f6SJed Brown   R = A; /* Upper triangular part of A now contains R, the rest contains the elementary reflectors */
1700194825f6SJed Brown 
1701194825f6SJed Brown   /* Extract an explicit representation of Q */
1702194825f6SJed Brown   Q = Ainv;
1703580bdb30SBarry Smith   ierr = PetscArraycpy(Q,A,mstride*n);CHKERRQ(ierr);
1704194825f6SJed Brown   K = N;                        /* full rank */
1705c964aadfSJose E. Roman   PetscStackCallBLAS("LAPACKorgqr",LAPACKorgqr_(&M,&N,&K,Q,&lda,tau,work,&ldwork,&info));
1706194825f6SJed Brown   if (info) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"xORGQR/xUNGQR error");
1707194825f6SJed Brown 
1708194825f6SJed Brown   /* Compute A^{-T} = (R^{-1} Q^T)^T = Q R^{-T} */
1709194825f6SJed Brown   Alpha = 1.0;
1710194825f6SJed Brown   ldb = lda;
1711001a771dSBarry Smith   PetscStackCallBLAS("BLAStrsm",BLAStrsm_("Right","Upper","ConjugateTranspose","NotUnitTriangular",&M,&N,&Alpha,R,&lda,Q,&ldb));
1712194825f6SJed Brown   /* Ainv is Q, overwritten with inverse */
1713194825f6SJed Brown 
1714194825f6SJed Brown #if defined(PETSC_USE_COMPLEX)
1715194825f6SJed Brown   {
1716194825f6SJed Brown     PetscInt i;
1717194825f6SJed Brown     for (i=0; i<m*n; i++) Ainv_out[i] = PetscRealPart(Ainv[i]);
1718194825f6SJed Brown     ierr = PetscFree2(A,Ainv);CHKERRQ(ierr);
1719194825f6SJed Brown   }
1720194825f6SJed Brown #endif
1721194825f6SJed Brown   PetscFunctionReturn(0);
1722194825f6SJed Brown }
1723194825f6SJed Brown 
1724194825f6SJed Brown /* Computes integral of L_p' over intervals {(x0,x1),(x1,x2),...} */
1725194825f6SJed Brown static PetscErrorCode PetscDTLegendreIntegrate(PetscInt ninterval,const PetscReal *x,PetscInt ndegree,const PetscInt *degrees,PetscBool Transpose,PetscReal *B)
1726194825f6SJed Brown {
1727194825f6SJed Brown   PetscErrorCode ierr;
1728194825f6SJed Brown   PetscReal      *Bv;
1729194825f6SJed Brown   PetscInt       i,j;
1730194825f6SJed Brown 
1731194825f6SJed Brown   PetscFunctionBegin;
1732785e854fSJed Brown   ierr = PetscMalloc1((ninterval+1)*ndegree,&Bv);CHKERRQ(ierr);
1733194825f6SJed Brown   /* Point evaluation of L_p on all the source vertices */
1734194825f6SJed Brown   ierr = PetscDTLegendreEval(ninterval+1,x,ndegree,degrees,Bv,NULL,NULL);CHKERRQ(ierr);
1735194825f6SJed Brown   /* Integral over each interval: \int_a^b L_p' = L_p(b)-L_p(a) */
1736194825f6SJed Brown   for (i=0; i<ninterval; i++) {
1737194825f6SJed Brown     for (j=0; j<ndegree; j++) {
1738194825f6SJed Brown       if (Transpose) B[i+ninterval*j] = Bv[(i+1)*ndegree+j] - Bv[i*ndegree+j];
1739194825f6SJed Brown       else           B[i*ndegree+j]   = Bv[(i+1)*ndegree+j] - Bv[i*ndegree+j];
1740194825f6SJed Brown     }
1741194825f6SJed Brown   }
1742194825f6SJed Brown   ierr = PetscFree(Bv);CHKERRQ(ierr);
1743194825f6SJed Brown   PetscFunctionReturn(0);
1744194825f6SJed Brown }
1745194825f6SJed Brown 
1746194825f6SJed Brown /*@
1747194825f6SJed Brown    PetscDTReconstructPoly - create matrix representing polynomial reconstruction using cell intervals and evaluation at target intervals
1748194825f6SJed Brown 
1749194825f6SJed Brown    Not Collective
1750194825f6SJed Brown 
1751194825f6SJed Brown    Input Arguments:
1752194825f6SJed Brown +  degree - degree of reconstruction polynomial
1753194825f6SJed Brown .  nsource - number of source intervals
1754194825f6SJed Brown .  sourcex - sorted coordinates of source cell boundaries (length nsource+1)
1755194825f6SJed Brown .  ntarget - number of target intervals
1756194825f6SJed Brown -  targetx - sorted coordinates of target cell boundaries (length ntarget+1)
1757194825f6SJed Brown 
1758194825f6SJed Brown    Output Arguments:
1759194825f6SJed Brown .  R - reconstruction matrix, utarget = sum_s R[t*nsource+s] * usource[s]
1760194825f6SJed Brown 
1761194825f6SJed Brown    Level: advanced
1762194825f6SJed Brown 
1763194825f6SJed Brown .seealso: PetscDTLegendreEval()
1764194825f6SJed Brown @*/
1765194825f6SJed Brown PetscErrorCode PetscDTReconstructPoly(PetscInt degree,PetscInt nsource,const PetscReal *sourcex,PetscInt ntarget,const PetscReal *targetx,PetscReal *R)
1766194825f6SJed Brown {
1767194825f6SJed Brown   PetscErrorCode ierr;
1768194825f6SJed Brown   PetscInt       i,j,k,*bdegrees,worksize;
1769194825f6SJed Brown   PetscReal      xmin,xmax,center,hscale,*sourcey,*targety,*Bsource,*Bsinv,*Btarget;
1770194825f6SJed Brown   PetscScalar    *tau,*work;
1771194825f6SJed Brown 
1772194825f6SJed Brown   PetscFunctionBegin;
1773194825f6SJed Brown   PetscValidRealPointer(sourcex,3);
1774194825f6SJed Brown   PetscValidRealPointer(targetx,5);
1775194825f6SJed Brown   PetscValidRealPointer(R,6);
1776194825f6SJed Brown   if (degree >= nsource) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Reconstruction degree %D must be less than number of source intervals %D",degree,nsource);
1777194825f6SJed Brown #if defined(PETSC_USE_DEBUG)
1778194825f6SJed Brown   for (i=0; i<nsource; i++) {
177957622a8eSBarry Smith     if (sourcex[i] >= sourcex[i+1]) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_CORRUPT,"Source interval %D has negative orientation (%g,%g)",i,(double)sourcex[i],(double)sourcex[i+1]);
1780194825f6SJed Brown   }
1781194825f6SJed Brown   for (i=0; i<ntarget; i++) {
178257622a8eSBarry Smith     if (targetx[i] >= targetx[i+1]) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_CORRUPT,"Target interval %D has negative orientation (%g,%g)",i,(double)targetx[i],(double)targetx[i+1]);
1783194825f6SJed Brown   }
1784194825f6SJed Brown #endif
1785194825f6SJed Brown   xmin = PetscMin(sourcex[0],targetx[0]);
1786194825f6SJed Brown   xmax = PetscMax(sourcex[nsource],targetx[ntarget]);
1787194825f6SJed Brown   center = (xmin + xmax)/2;
1788194825f6SJed Brown   hscale = (xmax - xmin)/2;
1789194825f6SJed Brown   worksize = nsource;
1790dcca6d9dSJed Brown   ierr = PetscMalloc4(degree+1,&bdegrees,nsource+1,&sourcey,nsource*(degree+1),&Bsource,worksize,&work);CHKERRQ(ierr);
1791dcca6d9dSJed Brown   ierr = PetscMalloc4(nsource,&tau,nsource*(degree+1),&Bsinv,ntarget+1,&targety,ntarget*(degree+1),&Btarget);CHKERRQ(ierr);
1792194825f6SJed Brown   for (i=0; i<=nsource; i++) sourcey[i] = (sourcex[i]-center)/hscale;
1793194825f6SJed Brown   for (i=0; i<=degree; i++) bdegrees[i] = i+1;
1794194825f6SJed Brown   ierr = PetscDTLegendreIntegrate(nsource,sourcey,degree+1,bdegrees,PETSC_TRUE,Bsource);CHKERRQ(ierr);
1795194825f6SJed Brown   ierr = PetscDTPseudoInverseQR(nsource,nsource,degree+1,Bsource,Bsinv,tau,nsource,work);CHKERRQ(ierr);
1796194825f6SJed Brown   for (i=0; i<=ntarget; i++) targety[i] = (targetx[i]-center)/hscale;
1797194825f6SJed Brown   ierr = PetscDTLegendreIntegrate(ntarget,targety,degree+1,bdegrees,PETSC_FALSE,Btarget);CHKERRQ(ierr);
1798194825f6SJed Brown   for (i=0; i<ntarget; i++) {
1799194825f6SJed Brown     PetscReal rowsum = 0;
1800194825f6SJed Brown     for (j=0; j<nsource; j++) {
1801194825f6SJed Brown       PetscReal sum = 0;
1802194825f6SJed Brown       for (k=0; k<degree+1; k++) {
1803194825f6SJed Brown         sum += Btarget[i*(degree+1)+k] * Bsinv[k*nsource+j];
1804194825f6SJed Brown       }
1805194825f6SJed Brown       R[i*nsource+j] = sum;
1806194825f6SJed Brown       rowsum += sum;
1807194825f6SJed Brown     }
1808194825f6SJed Brown     for (j=0; j<nsource; j++) R[i*nsource+j] /= rowsum; /* normalize each row */
1809194825f6SJed Brown   }
1810194825f6SJed Brown   ierr = PetscFree4(bdegrees,sourcey,Bsource,work);CHKERRQ(ierr);
1811194825f6SJed Brown   ierr = PetscFree4(tau,Bsinv,targety,Btarget);CHKERRQ(ierr);
1812194825f6SJed Brown   PetscFunctionReturn(0);
1813194825f6SJed Brown }
1814916e780bShannah_mairs 
1815916e780bShannah_mairs /*@C
1816916e780bShannah_mairs    PetscGaussLobattoLegendreIntegrate - Compute the L2 integral of a function on the GLL points
1817916e780bShannah_mairs 
1818916e780bShannah_mairs    Not Collective
1819916e780bShannah_mairs 
1820916e780bShannah_mairs    Input Parameter:
1821916e780bShannah_mairs +  n - the number of GLL nodes
1822916e780bShannah_mairs .  nodes - the GLL nodes
1823916e780bShannah_mairs .  weights - the GLL weights
1824916e780bShannah_mairs .  f - the function values at the nodes
1825916e780bShannah_mairs 
1826916e780bShannah_mairs    Output Parameter:
1827916e780bShannah_mairs .  in - the value of the integral
1828916e780bShannah_mairs 
1829916e780bShannah_mairs    Level: beginner
1830916e780bShannah_mairs 
1831916e780bShannah_mairs .seealso: PetscDTGaussLobattoLegendreQuadrature()
1832916e780bShannah_mairs 
1833916e780bShannah_mairs @*/
1834916e780bShannah_mairs PetscErrorCode PetscGaussLobattoLegendreIntegrate(PetscInt n,PetscReal *nodes,PetscReal *weights,const PetscReal *f,PetscReal *in)
1835916e780bShannah_mairs {
1836916e780bShannah_mairs   PetscInt          i;
1837916e780bShannah_mairs 
1838916e780bShannah_mairs   PetscFunctionBegin;
1839916e780bShannah_mairs   *in = 0.;
1840916e780bShannah_mairs   for (i=0; i<n; i++) {
1841916e780bShannah_mairs     *in += f[i]*f[i]*weights[i];
1842916e780bShannah_mairs   }
1843916e780bShannah_mairs   PetscFunctionReturn(0);
1844916e780bShannah_mairs }
1845916e780bShannah_mairs 
1846916e780bShannah_mairs /*@C
1847916e780bShannah_mairs    PetscGaussLobattoLegendreElementLaplacianCreate - computes the Laplacian for a single 1d GLL element
1848916e780bShannah_mairs 
1849916e780bShannah_mairs    Not Collective
1850916e780bShannah_mairs 
1851916e780bShannah_mairs    Input Parameter:
1852916e780bShannah_mairs +  n - the number of GLL nodes
1853916e780bShannah_mairs .  nodes - the GLL nodes
1854916e780bShannah_mairs .  weights - the GLL weights
1855916e780bShannah_mairs 
1856916e780bShannah_mairs    Output Parameter:
1857916e780bShannah_mairs .  A - the stiffness element
1858916e780bShannah_mairs 
1859916e780bShannah_mairs    Level: beginner
1860916e780bShannah_mairs 
1861916e780bShannah_mairs    Notes:
1862916e780bShannah_mairs     Destroy this with PetscGaussLobattoLegendreElementLaplacianDestroy()
1863916e780bShannah_mairs 
1864916e780bShannah_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)
1865916e780bShannah_mairs 
1866916e780bShannah_mairs .seealso: PetscDTGaussLobattoLegendreQuadrature(), PetscGaussLobattoLegendreElementLaplacianDestroy()
1867916e780bShannah_mairs 
1868916e780bShannah_mairs @*/
1869916e780bShannah_mairs PetscErrorCode PetscGaussLobattoLegendreElementLaplacianCreate(PetscInt n,PetscReal *nodes,PetscReal *weights,PetscReal ***AA)
1870916e780bShannah_mairs {
1871916e780bShannah_mairs   PetscReal        **A;
1872916e780bShannah_mairs   PetscErrorCode  ierr;
1873916e780bShannah_mairs   const PetscReal  *gllnodes = nodes;
1874916e780bShannah_mairs   const PetscInt   p = n-1;
1875916e780bShannah_mairs   PetscReal        z0,z1,z2 = -1,x,Lpj,Lpr;
1876916e780bShannah_mairs   PetscInt         i,j,nn,r;
1877916e780bShannah_mairs 
1878916e780bShannah_mairs   PetscFunctionBegin;
1879916e780bShannah_mairs   ierr = PetscMalloc1(n,&A);CHKERRQ(ierr);
1880916e780bShannah_mairs   ierr = PetscMalloc1(n*n,&A[0]);CHKERRQ(ierr);
1881916e780bShannah_mairs   for (i=1; i<n; i++) A[i] = A[i-1]+n;
1882916e780bShannah_mairs 
1883916e780bShannah_mairs   for (j=1; j<p; j++) {
1884916e780bShannah_mairs     x  = gllnodes[j];
1885916e780bShannah_mairs     z0 = 1.;
1886916e780bShannah_mairs     z1 = x;
1887916e780bShannah_mairs     for (nn=1; nn<p; nn++) {
1888916e780bShannah_mairs       z2 = x*z1*(2.*((PetscReal)nn)+1.)/(((PetscReal)nn)+1.)-z0*(((PetscReal)nn)/(((PetscReal)nn)+1.));
1889916e780bShannah_mairs       z0 = z1;
1890916e780bShannah_mairs       z1 = z2;
1891916e780bShannah_mairs     }
1892916e780bShannah_mairs     Lpj=z2;
1893916e780bShannah_mairs     for (r=1; r<p; r++) {
1894916e780bShannah_mairs       if (r == j) {
1895916e780bShannah_mairs         A[j][j]=2./(3.*(1.-gllnodes[j]*gllnodes[j])*Lpj*Lpj);
1896916e780bShannah_mairs       } else {
1897916e780bShannah_mairs         x  = gllnodes[r];
1898916e780bShannah_mairs         z0 = 1.;
1899916e780bShannah_mairs         z1 = x;
1900916e780bShannah_mairs         for (nn=1; nn<p; nn++) {
1901916e780bShannah_mairs           z2 = x*z1*(2.*((PetscReal)nn)+1.)/(((PetscReal)nn)+1.)-z0*(((PetscReal)nn)/(((PetscReal)nn)+1.));
1902916e780bShannah_mairs           z0 = z1;
1903916e780bShannah_mairs           z1 = z2;
1904916e780bShannah_mairs         }
1905916e780bShannah_mairs         Lpr     = z2;
1906916e780bShannah_mairs         A[r][j] = 4./(((PetscReal)p)*(((PetscReal)p)+1.)*Lpj*Lpr*(gllnodes[j]-gllnodes[r])*(gllnodes[j]-gllnodes[r]));
1907916e780bShannah_mairs       }
1908916e780bShannah_mairs     }
1909916e780bShannah_mairs   }
1910916e780bShannah_mairs   for (j=1; j<p+1; j++) {
1911916e780bShannah_mairs     x  = gllnodes[j];
1912916e780bShannah_mairs     z0 = 1.;
1913916e780bShannah_mairs     z1 = x;
1914916e780bShannah_mairs     for (nn=1; nn<p; nn++) {
1915916e780bShannah_mairs       z2 = x*z1*(2.*((PetscReal)nn)+1.)/(((PetscReal)nn)+1.)-z0*(((PetscReal)nn)/(((PetscReal)nn)+1.));
1916916e780bShannah_mairs       z0 = z1;
1917916e780bShannah_mairs       z1 = z2;
1918916e780bShannah_mairs     }
1919916e780bShannah_mairs     Lpj     = z2;
1920916e780bShannah_mairs     A[j][0] = 4.*PetscPowRealInt(-1.,p)/(((PetscReal)p)*(((PetscReal)p)+1.)*Lpj*(1.+gllnodes[j])*(1.+gllnodes[j]));
1921916e780bShannah_mairs     A[0][j] = A[j][0];
1922916e780bShannah_mairs   }
1923916e780bShannah_mairs   for (j=0; j<p; j++) {
1924916e780bShannah_mairs     x  = gllnodes[j];
1925916e780bShannah_mairs     z0 = 1.;
1926916e780bShannah_mairs     z1 = x;
1927916e780bShannah_mairs     for (nn=1; nn<p; nn++) {
1928916e780bShannah_mairs       z2 = x*z1*(2.*((PetscReal)nn)+1.)/(((PetscReal)nn)+1.)-z0*(((PetscReal)nn)/(((PetscReal)nn)+1.));
1929916e780bShannah_mairs       z0 = z1;
1930916e780bShannah_mairs       z1 = z2;
1931916e780bShannah_mairs     }
1932916e780bShannah_mairs     Lpj=z2;
1933916e780bShannah_mairs 
1934916e780bShannah_mairs     A[p][j] = 4./(((PetscReal)p)*(((PetscReal)p)+1.)*Lpj*(1.-gllnodes[j])*(1.-gllnodes[j]));
1935916e780bShannah_mairs     A[j][p] = A[p][j];
1936916e780bShannah_mairs   }
1937916e780bShannah_mairs   A[0][0]=0.5+(((PetscReal)p)*(((PetscReal)p)+1.)-2.)/6.;
1938916e780bShannah_mairs   A[p][p]=A[0][0];
1939916e780bShannah_mairs   *AA = A;
1940916e780bShannah_mairs   PetscFunctionReturn(0);
1941916e780bShannah_mairs }
1942916e780bShannah_mairs 
1943916e780bShannah_mairs /*@C
1944916e780bShannah_mairs    PetscGaussLobattoLegendreElementLaplacianDestroy - frees the Laplacian for a single 1d GLL element
1945916e780bShannah_mairs 
1946916e780bShannah_mairs    Not Collective
1947916e780bShannah_mairs 
1948916e780bShannah_mairs    Input Parameter:
1949916e780bShannah_mairs +  n - the number of GLL nodes
1950916e780bShannah_mairs .  nodes - the GLL nodes
1951916e780bShannah_mairs .  weights - the GLL weightss
1952916e780bShannah_mairs -  A - the stiffness element
1953916e780bShannah_mairs 
1954916e780bShannah_mairs    Level: beginner
1955916e780bShannah_mairs 
1956916e780bShannah_mairs .seealso: PetscDTGaussLobattoLegendreQuadrature(), PetscGaussLobattoLegendreElementLaplacianCreate()
1957916e780bShannah_mairs 
1958916e780bShannah_mairs @*/
1959916e780bShannah_mairs PetscErrorCode PetscGaussLobattoLegendreElementLaplacianDestroy(PetscInt n,PetscReal *nodes,PetscReal *weights,PetscReal ***AA)
1960916e780bShannah_mairs {
1961916e780bShannah_mairs   PetscErrorCode ierr;
1962916e780bShannah_mairs 
1963916e780bShannah_mairs   PetscFunctionBegin;
1964916e780bShannah_mairs   ierr = PetscFree((*AA)[0]);CHKERRQ(ierr);
1965916e780bShannah_mairs   ierr = PetscFree(*AA);CHKERRQ(ierr);
1966916e780bShannah_mairs   *AA  = NULL;
1967916e780bShannah_mairs   PetscFunctionReturn(0);
1968916e780bShannah_mairs }
1969916e780bShannah_mairs 
1970916e780bShannah_mairs /*@C
1971916e780bShannah_mairs    PetscGaussLobattoLegendreElementGradientCreate - computes the gradient for a single 1d GLL element
1972916e780bShannah_mairs 
1973916e780bShannah_mairs    Not Collective
1974916e780bShannah_mairs 
1975916e780bShannah_mairs    Input Parameter:
1976916e780bShannah_mairs +  n - the number of GLL nodes
1977916e780bShannah_mairs .  nodes - the GLL nodes
1978916e780bShannah_mairs .  weights - the GLL weights
1979916e780bShannah_mairs 
1980916e780bShannah_mairs    Output Parameter:
1981916e780bShannah_mairs .  AA - the stiffness element
1982916e780bShannah_mairs -  AAT - the transpose of AA (pass in NULL if you do not need this array)
1983916e780bShannah_mairs 
1984916e780bShannah_mairs    Level: beginner
1985916e780bShannah_mairs 
1986916e780bShannah_mairs    Notes:
1987916e780bShannah_mairs     Destroy this with PetscGaussLobattoLegendreElementGradientDestroy()
1988916e780bShannah_mairs 
1989916e780bShannah_mairs    You can access entries in these arrays with AA[i][j] but in memory it is stored in contiguous memory, row oriented
1990916e780bShannah_mairs 
1991916e780bShannah_mairs .seealso: PetscDTGaussLobattoLegendreQuadrature(), PetscGaussLobattoLegendreElementLaplacianDestroy()
1992916e780bShannah_mairs 
1993916e780bShannah_mairs @*/
1994916e780bShannah_mairs PetscErrorCode PetscGaussLobattoLegendreElementGradientCreate(PetscInt n,PetscReal *nodes,PetscReal *weights,PetscReal ***AA,PetscReal ***AAT)
1995916e780bShannah_mairs {
1996916e780bShannah_mairs   PetscReal        **A, **AT = NULL;
1997916e780bShannah_mairs   PetscErrorCode  ierr;
1998916e780bShannah_mairs   const PetscReal  *gllnodes = nodes;
1999916e780bShannah_mairs   const PetscInt   p = n-1;
2000e6a796c3SToby Isaac   PetscReal        Li, Lj,d0;
2001916e780bShannah_mairs   PetscInt         i,j;
2002916e780bShannah_mairs 
2003916e780bShannah_mairs   PetscFunctionBegin;
2004916e780bShannah_mairs   ierr = PetscMalloc1(n,&A);CHKERRQ(ierr);
2005916e780bShannah_mairs   ierr = PetscMalloc1(n*n,&A[0]);CHKERRQ(ierr);
2006916e780bShannah_mairs   for (i=1; i<n; i++) A[i] = A[i-1]+n;
2007916e780bShannah_mairs 
2008916e780bShannah_mairs   if (AAT) {
2009916e780bShannah_mairs     ierr = PetscMalloc1(n,&AT);CHKERRQ(ierr);
2010916e780bShannah_mairs     ierr = PetscMalloc1(n*n,&AT[0]);CHKERRQ(ierr);
2011916e780bShannah_mairs     for (i=1; i<n; i++) AT[i] = AT[i-1]+n;
2012916e780bShannah_mairs   }
2013916e780bShannah_mairs 
2014916e780bShannah_mairs   if (n==1) {A[0][0] = 0.;}
2015916e780bShannah_mairs   d0 = (PetscReal)p*((PetscReal)p+1.)/4.;
2016916e780bShannah_mairs   for  (i=0; i<n; i++) {
2017916e780bShannah_mairs     for  (j=0; j<n; j++) {
2018916e780bShannah_mairs       A[i][j] = 0.;
2019e6a796c3SToby Isaac       ierr = PetscDTComputeJacobi(0., 0., p, gllnodes[i], &Li);CHKERRQ(ierr);
2020e6a796c3SToby Isaac       ierr = PetscDTComputeJacobi(0., 0., p, gllnodes[j], &Lj);CHKERRQ(ierr);
2021916e780bShannah_mairs       if (i!=j)             A[i][j] = Li/(Lj*(gllnodes[i]-gllnodes[j]));
2022916e780bShannah_mairs       if ((j==i) && (i==0)) A[i][j] = -d0;
2023916e780bShannah_mairs       if (j==i && i==p)     A[i][j] = d0;
2024916e780bShannah_mairs       if (AT) AT[j][i] = A[i][j];
2025916e780bShannah_mairs     }
2026916e780bShannah_mairs   }
2027916e780bShannah_mairs   if (AAT) *AAT = AT;
2028916e780bShannah_mairs   *AA  = A;
2029916e780bShannah_mairs   PetscFunctionReturn(0);
2030916e780bShannah_mairs }
2031916e780bShannah_mairs 
2032916e780bShannah_mairs /*@C
2033916e780bShannah_mairs    PetscGaussLobattoLegendreElementGradientDestroy - frees the gradient for a single 1d GLL element obtained with PetscGaussLobattoLegendreElementGradientCreate()
2034916e780bShannah_mairs 
2035916e780bShannah_mairs    Not Collective
2036916e780bShannah_mairs 
2037916e780bShannah_mairs    Input Parameter:
2038916e780bShannah_mairs +  n - the number of GLL nodes
2039916e780bShannah_mairs .  nodes - the GLL nodes
2040916e780bShannah_mairs .  weights - the GLL weights
2041916e780bShannah_mairs .  AA - the stiffness element
2042916e780bShannah_mairs -  AAT - the transpose of the element
2043916e780bShannah_mairs 
2044916e780bShannah_mairs    Level: beginner
2045916e780bShannah_mairs 
2046916e780bShannah_mairs .seealso: PetscDTGaussLobattoLegendreQuadrature(), PetscGaussLobattoLegendreElementLaplacianCreate(), PetscGaussLobattoLegendreElementAdvectionCreate()
2047916e780bShannah_mairs 
2048916e780bShannah_mairs @*/
2049916e780bShannah_mairs PetscErrorCode PetscGaussLobattoLegendreElementGradientDestroy(PetscInt n,PetscReal *nodes,PetscReal *weights,PetscReal ***AA,PetscReal ***AAT)
2050916e780bShannah_mairs {
2051916e780bShannah_mairs   PetscErrorCode ierr;
2052916e780bShannah_mairs 
2053916e780bShannah_mairs   PetscFunctionBegin;
2054916e780bShannah_mairs   ierr = PetscFree((*AA)[0]);CHKERRQ(ierr);
2055916e780bShannah_mairs   ierr = PetscFree(*AA);CHKERRQ(ierr);
2056916e780bShannah_mairs   *AA  = NULL;
2057916e780bShannah_mairs   if (*AAT) {
2058916e780bShannah_mairs     ierr = PetscFree((*AAT)[0]);CHKERRQ(ierr);
2059916e780bShannah_mairs     ierr = PetscFree(*AAT);CHKERRQ(ierr);
2060916e780bShannah_mairs     *AAT  = NULL;
2061916e780bShannah_mairs   }
2062916e780bShannah_mairs   PetscFunctionReturn(0);
2063916e780bShannah_mairs }
2064916e780bShannah_mairs 
2065916e780bShannah_mairs /*@C
2066916e780bShannah_mairs    PetscGaussLobattoLegendreElementAdvectionCreate - computes the advection operator for a single 1d GLL element
2067916e780bShannah_mairs 
2068916e780bShannah_mairs    Not Collective
2069916e780bShannah_mairs 
2070916e780bShannah_mairs    Input Parameter:
2071916e780bShannah_mairs +  n - the number of GLL nodes
2072916e780bShannah_mairs .  nodes - the GLL nodes
2073916e780bShannah_mairs .  weights - the GLL weightss
2074916e780bShannah_mairs 
2075916e780bShannah_mairs    Output Parameter:
2076916e780bShannah_mairs .  AA - the stiffness element
2077916e780bShannah_mairs 
2078916e780bShannah_mairs    Level: beginner
2079916e780bShannah_mairs 
2080916e780bShannah_mairs    Notes:
2081916e780bShannah_mairs     Destroy this with PetscGaussLobattoLegendreElementAdvectionDestroy()
2082916e780bShannah_mairs 
2083916e780bShannah_mairs    This is the same as the Gradient operator multiplied by the diagonal mass matrix
2084916e780bShannah_mairs 
2085916e780bShannah_mairs    You can access entries in this array with AA[i][j] but in memory it is stored in contiguous memory, row oriented
2086916e780bShannah_mairs 
2087916e780bShannah_mairs .seealso: PetscDTGaussLobattoLegendreQuadrature(), PetscGaussLobattoLegendreElementLaplacianCreate(), PetscGaussLobattoLegendreElementAdvectionDestroy()
2088916e780bShannah_mairs 
2089916e780bShannah_mairs @*/
2090916e780bShannah_mairs PetscErrorCode PetscGaussLobattoLegendreElementAdvectionCreate(PetscInt n,PetscReal *nodes,PetscReal *weights,PetscReal ***AA)
2091916e780bShannah_mairs {
2092916e780bShannah_mairs   PetscReal       **D;
2093916e780bShannah_mairs   PetscErrorCode  ierr;
2094916e780bShannah_mairs   const PetscReal  *gllweights = weights;
2095916e780bShannah_mairs   const PetscInt   glln = n;
2096916e780bShannah_mairs   PetscInt         i,j;
2097916e780bShannah_mairs 
2098916e780bShannah_mairs   PetscFunctionBegin;
2099916e780bShannah_mairs   ierr = PetscGaussLobattoLegendreElementGradientCreate(n,nodes,weights,&D,NULL);CHKERRQ(ierr);
2100916e780bShannah_mairs   for (i=0; i<glln; i++){
2101916e780bShannah_mairs     for (j=0; j<glln; j++) {
2102916e780bShannah_mairs       D[i][j] = gllweights[i]*D[i][j];
2103916e780bShannah_mairs     }
2104916e780bShannah_mairs   }
2105916e780bShannah_mairs   *AA = D;
2106916e780bShannah_mairs   PetscFunctionReturn(0);
2107916e780bShannah_mairs }
2108916e780bShannah_mairs 
2109916e780bShannah_mairs /*@C
2110916e780bShannah_mairs    PetscGaussLobattoLegendreElementAdvectionDestroy - frees the advection stiffness for a single 1d GLL element
2111916e780bShannah_mairs 
2112916e780bShannah_mairs    Not Collective
2113916e780bShannah_mairs 
2114916e780bShannah_mairs    Input Parameter:
2115916e780bShannah_mairs +  n - the number of GLL nodes
2116916e780bShannah_mairs .  nodes - the GLL nodes
2117916e780bShannah_mairs .  weights - the GLL weights
2118916e780bShannah_mairs -  A - advection
2119916e780bShannah_mairs 
2120916e780bShannah_mairs    Level: beginner
2121916e780bShannah_mairs 
2122916e780bShannah_mairs .seealso: PetscDTGaussLobattoLegendreQuadrature(), PetscGaussLobattoLegendreElementAdvectionCreate()
2123916e780bShannah_mairs 
2124916e780bShannah_mairs @*/
2125916e780bShannah_mairs PetscErrorCode PetscGaussLobattoLegendreElementAdvectionDestroy(PetscInt n,PetscReal *nodes,PetscReal *weights,PetscReal ***AA)
2126916e780bShannah_mairs {
2127916e780bShannah_mairs   PetscErrorCode ierr;
2128916e780bShannah_mairs 
2129916e780bShannah_mairs   PetscFunctionBegin;
2130916e780bShannah_mairs   ierr = PetscFree((*AA)[0]);CHKERRQ(ierr);
2131916e780bShannah_mairs   ierr = PetscFree(*AA);CHKERRQ(ierr);
2132916e780bShannah_mairs   *AA  = NULL;
2133916e780bShannah_mairs   PetscFunctionReturn(0);
2134916e780bShannah_mairs }
2135916e780bShannah_mairs 
2136916e780bShannah_mairs PetscErrorCode PetscGaussLobattoLegendreElementMassCreate(PetscInt n,PetscReal *nodes,PetscReal *weights,PetscReal ***AA)
2137916e780bShannah_mairs {
2138916e780bShannah_mairs   PetscReal        **A;
2139916e780bShannah_mairs   PetscErrorCode  ierr;
2140916e780bShannah_mairs   const PetscReal  *gllweights = weights;
2141916e780bShannah_mairs   const PetscInt   glln = n;
2142916e780bShannah_mairs   PetscInt         i,j;
2143916e780bShannah_mairs 
2144916e780bShannah_mairs   PetscFunctionBegin;
2145916e780bShannah_mairs   ierr = PetscMalloc1(glln,&A);CHKERRQ(ierr);
2146916e780bShannah_mairs   ierr = PetscMalloc1(glln*glln,&A[0]);CHKERRQ(ierr);
2147916e780bShannah_mairs   for (i=1; i<glln; i++) A[i] = A[i-1]+glln;
2148916e780bShannah_mairs   if (glln==1) {A[0][0] = 0.;}
2149916e780bShannah_mairs   for  (i=0; i<glln; i++) {
2150916e780bShannah_mairs     for  (j=0; j<glln; j++) {
2151916e780bShannah_mairs       A[i][j] = 0.;
2152916e780bShannah_mairs       if (j==i)     A[i][j] = gllweights[i];
2153916e780bShannah_mairs     }
2154916e780bShannah_mairs   }
2155916e780bShannah_mairs   *AA  = A;
2156916e780bShannah_mairs   PetscFunctionReturn(0);
2157916e780bShannah_mairs }
2158916e780bShannah_mairs 
2159916e780bShannah_mairs PetscErrorCode PetscGaussLobattoLegendreElementMassDestroy(PetscInt n,PetscReal *nodes,PetscReal *weights,PetscReal ***AA)
2160916e780bShannah_mairs {
2161916e780bShannah_mairs   PetscErrorCode ierr;
2162916e780bShannah_mairs 
2163916e780bShannah_mairs   PetscFunctionBegin;
2164916e780bShannah_mairs   ierr = PetscFree((*AA)[0]);CHKERRQ(ierr);
2165916e780bShannah_mairs   ierr = PetscFree(*AA);CHKERRQ(ierr);
2166916e780bShannah_mairs   *AA  = NULL;
2167916e780bShannah_mairs   PetscFunctionReturn(0);
2168916e780bShannah_mairs }
2169