xref: /petsc/src/dm/dt/interface/dt.c (revision c4762a1b19cd2af06abeed90e8f9d34fb975dd94)
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*c4762a1bSJed Brown /* Numerical tests in src/dm/dt/tests/ex1.c show that when computing the nodes and weights of Gauss-Jacobi
2694e21283SToby Isaac    quadrature rules:
27e6a796c3SToby Isaac 
2894e21283SToby Isaac    - in double precision, Newton's method and Golub & Welsch both work for moderate degrees (< 100),
2994e21283SToby Isaac    - in single precision, Newton's method starts producing incorrect roots around n = 15, but
3094e21283SToby Isaac      the weights from Golub & Welsch become a problem before then: they produces errors
3194e21283SToby Isaac      in computing the Jacobi-polynomial Gram matrix around n = 6.
3294e21283SToby Isaac 
3394e21283SToby Isaac    So we default to Newton's method (required fewer dependencies) */
3494e21283SToby 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 
60194e21283SToby Isaac /* Compute the coefficients for the Jacobi polynomial recurrence,
60294e21283SToby Isaac  *
60394e21283SToby Isaac  * J^{a,b}_n(x) = (cnm1 + cnm1x * x) * J^{a,b}_{n-1}(x) - cnm2 * J^{a,b}_{n-2}(x).
60494e21283SToby Isaac  */
60594e21283SToby Isaac #define PetscDTJacobiRecurrence_Internal(n,a,b,cnm1,cnm1x,cnm2) \
60694e21283SToby Isaac do {                                                            \
60794e21283SToby Isaac   PetscReal _a = (a);                                           \
60894e21283SToby Isaac   PetscReal _b = (b);                                           \
60994e21283SToby Isaac   PetscReal _n = (n);                                           \
61094e21283SToby Isaac   if (n == 1) {                                                 \
61194e21283SToby Isaac     (cnm1) = (_a-_b) * 0.5;                                     \
61294e21283SToby Isaac     (cnm1x) = (_a+_b+2.)*0.5;                                   \
61394e21283SToby Isaac     (cnm2) = 0.;                                                \
61494e21283SToby Isaac   } else {                                                      \
61594e21283SToby Isaac     PetscReal _2n = _n+_n;                                      \
61694e21283SToby Isaac     PetscReal _d = (_2n*(_n+_a+_b)*(_2n+_a+_b-2));              \
61794e21283SToby Isaac     PetscReal _n1 = (_2n+_a+_b-1.)*(_a*_a-_b*_b);               \
61894e21283SToby Isaac     PetscReal _n1x = (_2n+_a+_b-1.)*(_2n+_a+_b)*(_2n+_a+_b-2);  \
61994e21283SToby Isaac     PetscReal _n2 = 2.*((_n+_a-1.)*(_n+_b-1.)*(_2n+_a+_b));     \
62094e21283SToby Isaac     (cnm1) = _n1 / _d;                                          \
62194e21283SToby Isaac     (cnm1x) = _n1x / _d;                                        \
62294e21283SToby Isaac     (cnm2) = _n2 / _d;                                          \
62394e21283SToby Isaac   }                                                             \
62494e21283SToby Isaac } while (0)
62594e21283SToby Isaac 
62694e21283SToby Isaac static PetscErrorCode PetscDTJacobiEval_Internal(PetscInt npoints, PetscReal a, PetscReal b, PetscInt k, const PetscReal *points, PetscInt ndegree, const PetscInt *degrees, PetscReal *p)
62794e21283SToby Isaac {
62894e21283SToby Isaac   PetscReal ak, bk;
62994e21283SToby Isaac   PetscReal abk1;
63094e21283SToby Isaac   PetscInt i,l,maxdegree;
63194e21283SToby Isaac 
63294e21283SToby Isaac   PetscFunctionBegin;
63394e21283SToby Isaac   maxdegree = degrees[ndegree-1] - k;
63494e21283SToby Isaac   ak = a + k;
63594e21283SToby Isaac   bk = b + k;
63694e21283SToby Isaac   abk1 = a + b + k + 1.;
63794e21283SToby Isaac   if (maxdegree < 0) {
63894e21283SToby Isaac     for (i = 0; i < npoints; i++) for (l = 0; l < ndegree; l++) p[i*ndegree+l] = 0.;
63994e21283SToby Isaac     PetscFunctionReturn(0);
64094e21283SToby Isaac   }
64194e21283SToby Isaac   for (i=0; i<npoints; i++) {
64294e21283SToby Isaac     PetscReal pm1,pm2,x;
64394e21283SToby Isaac     PetscReal cnm1, cnm1x, cnm2;
64494e21283SToby Isaac     PetscInt  j,m;
64594e21283SToby Isaac 
64694e21283SToby Isaac     x    = points[i];
64794e21283SToby Isaac     pm2  = 1.;
64894e21283SToby Isaac     PetscDTJacobiRecurrence_Internal(1,ak,bk,cnm1,cnm1x,cnm2);
64994e21283SToby Isaac     pm1 = (cnm1 + cnm1x*x);
65094e21283SToby Isaac     l    = 0;
65194e21283SToby Isaac     while (l < ndegree && degrees[l] - k < 0) {
65294e21283SToby Isaac       p[l++] = 0.;
65394e21283SToby Isaac     }
65494e21283SToby Isaac     while (l < ndegree && degrees[l] - k == 0) {
65594e21283SToby Isaac       p[l] = pm2;
65694e21283SToby Isaac       for (m = 0; m < k; m++) p[l] *= (abk1 + m) * 0.5;
65794e21283SToby Isaac       l++;
65894e21283SToby Isaac     }
65994e21283SToby Isaac     while (l < ndegree && degrees[l] - k == 1) {
66094e21283SToby Isaac       p[l] = pm1;
66194e21283SToby Isaac       for (m = 0; m < k; m++) p[l] *= (abk1 + 1 + m) * 0.5;
66294e21283SToby Isaac       l++;
66394e21283SToby Isaac     }
66494e21283SToby Isaac     for (j=2; j<=maxdegree; j++) {
66594e21283SToby Isaac       PetscReal pp;
66694e21283SToby Isaac 
66794e21283SToby Isaac       PetscDTJacobiRecurrence_Internal(j,ak,bk,cnm1,cnm1x,cnm2);
66894e21283SToby Isaac       pp   = (cnm1 + cnm1x*x)*pm1 - cnm2*pm2;
66994e21283SToby Isaac       pm2  = pm1;
67094e21283SToby Isaac       pm1  = pp;
67194e21283SToby Isaac       while (l < ndegree && degrees[l] - k == j) {
67294e21283SToby Isaac         p[l] = pp;
67394e21283SToby Isaac         for (m = 0; m < k; m++) p[l] *= (abk1 + j + m) * 0.5;
67494e21283SToby Isaac         l++;
67594e21283SToby Isaac       }
67694e21283SToby Isaac     }
67794e21283SToby Isaac     p += ndegree;
67894e21283SToby Isaac   }
67994e21283SToby Isaac   PetscFunctionReturn(0);
68094e21283SToby Isaac }
68194e21283SToby Isaac 
68237045ce4SJed Brown /*@
68394e21283SToby Isaac    PetscDTJacobiEval - evaluate Jacobi polynomials for the weight function $(1.+x)^{\alpha} (1.-x)^{\beta}$
68494e21283SToby Isaac                        at points
68594e21283SToby Isaac 
68694e21283SToby Isaac    Not Collective
68794e21283SToby Isaac 
68894e21283SToby Isaac    Input Arguments:
68994e21283SToby Isaac +  npoints - number of spatial points to evaluate at
69094e21283SToby Isaac .  alpha - the left exponent > -1
69194e21283SToby Isaac .  beta - the right exponent > -1
69294e21283SToby Isaac .  points - array of locations to evaluate at
69394e21283SToby Isaac .  ndegree - number of basis degrees to evaluate
69494e21283SToby Isaac -  degrees - sorted array of degrees to evaluate
69594e21283SToby Isaac 
69694e21283SToby Isaac    Output Arguments:
69794e21283SToby Isaac +  B - row-oriented basis evaluation matrix B[point*ndegree + degree] (dimension npoints*ndegrees, allocated by caller) (or NULL)
69894e21283SToby Isaac .  D - row-oriented derivative evaluation matrix (or NULL)
69994e21283SToby Isaac -  D2 - row-oriented second derivative evaluation matrix (or NULL)
70094e21283SToby Isaac 
70194e21283SToby Isaac    Level: intermediate
70294e21283SToby Isaac 
70394e21283SToby Isaac .seealso: PetscDTGaussQuadrature()
70494e21283SToby Isaac @*/
70594e21283SToby Isaac PetscErrorCode PetscDTJacobiEval(PetscInt npoints,PetscReal alpha, PetscReal beta, const PetscReal *points,PetscInt ndegree,const PetscInt *degrees,PetscReal *B,PetscReal *D,PetscReal *D2)
70694e21283SToby Isaac {
70794e21283SToby Isaac   PetscErrorCode ierr;
70894e21283SToby Isaac 
70994e21283SToby Isaac   PetscFunctionBegin;
71094e21283SToby Isaac   if (alpha <= -1.) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"alpha must be > -1.");
71194e21283SToby Isaac   if (beta <= -1.) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"beta must be > -1.");
71294e21283SToby Isaac   if (!npoints || !ndegree) PetscFunctionReturn(0);
71394e21283SToby Isaac   if (B)  {ierr = PetscDTJacobiEval_Internal(npoints, alpha, beta, 0, points, ndegree, degrees, B);CHKERRQ(ierr);}
71494e21283SToby Isaac   if (D)  {ierr = PetscDTJacobiEval_Internal(npoints, alpha, beta, 1, points, ndegree, degrees, D);CHKERRQ(ierr);}
71594e21283SToby Isaac   if (D2) {ierr = PetscDTJacobiEval_Internal(npoints, alpha, beta, 2, points, ndegree, degrees, D2);CHKERRQ(ierr);}
71694e21283SToby Isaac   PetscFunctionReturn(0);
71794e21283SToby Isaac }
71894e21283SToby Isaac 
71994e21283SToby Isaac /*@
72094e21283SToby 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 {
74194e21283SToby Isaac   PetscErrorCode ierr;
74237045ce4SJed Brown 
74337045ce4SJed Brown   PetscFunctionBegin;
74494e21283SToby 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;
82694e21283SToby 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 {
84994e21283SToby Isaac   PetscReal pn1, pn2;
85094e21283SToby Isaac   PetscReal cnm1, cnm1x, cnm2;
851e6a796c3SToby Isaac   PetscInt  k;
852e6a796c3SToby Isaac 
853e6a796c3SToby Isaac   PetscFunctionBegin;
854e6a796c3SToby Isaac   if (!n) {*P = 1.0; PetscFunctionReturn(0);}
85594e21283SToby Isaac   PetscDTJacobiRecurrence_Internal(1,a,b,cnm1,cnm1x,cnm2);
85694e21283SToby Isaac   pn2 = 1.;
85794e21283SToby Isaac   pn1 = cnm1 + cnm1x*x;
85894e21283SToby Isaac   if (n == 1) {*P = pn1; PetscFunctionReturn(0);}
859e6a796c3SToby Isaac   *P  = 0.0;
860e6a796c3SToby Isaac   for (k = 2; k < n+1; ++k) {
86194e21283SToby Isaac     PetscDTJacobiRecurrence_Internal(k,a,b,cnm1,cnm1x,cnm2);
862e6a796c3SToby Isaac 
86394e21283SToby 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;
89794e21283SToby Isaac   PetscReal      eps     = PetscExpReal(0.75 * PetscLogReal(PETSC_MACHINE_EPSILON));
898200b5abcSJed Brown   PetscReal      a1, 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);
90594e21283SToby Isaac #if defined(PETSC_HAVE_LGAMMA)
906200b5abcSJed Brown   {
907200b5abcSJed Brown     PetscReal a2, a3, a4, a5;
90894e21283SToby Isaac     a2 = PetscLGamma(a + npoints + 1);
90994e21283SToby Isaac     a3 = PetscLGamma(b + npoints + 1);
91094e21283SToby Isaac     a4 = PetscLGamma(a + b + npoints + 1);
91194e21283SToby Isaac     a5 = PetscLGamma(npoints + 1);
91294e21283SToby Isaac     gf = PetscExpReal(a2 + a3 - (a4 + a5));
913200b5abcSJed Brown   }
914e6a796c3SToby Isaac #else
915e6a796c3SToby Isaac   {
916e6a796c3SToby Isaac     PetscInt ia, ib;
917e6a796c3SToby Isaac 
918e6a796c3SToby Isaac     ia = (PetscInt) a;
919e6a796c3SToby Isaac     ib = (PetscInt) b;
92094e21283SToby Isaac     gf = 1.;
92194e21283SToby Isaac     if (ia == a && ia >= 0) { /* compute ratio of rising factorals wrt a */
92294e21283SToby Isaac       for (k = 0; k < ia; k++) gf *= (npoints + 1. + k) / (npoints + b + 1. + k);
92394e21283SToby Isaac     } else if (b == b && ib >= 0) { /* compute ratio of rising factorials wrt b */
92494e21283SToby Isaac       for (k = 0; k < ib; k++) gf *= (npoints + 1. + k) / (npoints + a + 1. + k);
92594e21283SToby Isaac     } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"lgamma() - math routine is unavailable.");
926e6a796c3SToby Isaac   }
927e6a796c3SToby Isaac #endif
928e6a796c3SToby Isaac 
92994e21283SToby Isaac   a6   = a1 * gf;
930e6a796c3SToby Isaac   /* Computes the m roots of P_{m}^{a,b} on [-1,1] by Newton's method with Chebyshev points as initial guesses.
931e6a796c3SToby Isaac    Algorithm implemented from the pseudocode given by Karniadakis and Sherwin and Python in FIAT */
932e6a796c3SToby Isaac   for (k = 0; k < npoints; ++k) {
93394e21283SToby Isaac     PetscReal r = PetscCosReal(PETSC_PI * (1. - (4.*k + 3. + 2.*b) / (4.*npoints + 2.*(a + b + 1.)))), dP;
934e6a796c3SToby Isaac     PetscInt  j;
935e6a796c3SToby Isaac 
936e6a796c3SToby Isaac     if (k > 0) r = 0.5 * (r + x[k-1]);
937e6a796c3SToby Isaac     for (j = 0; j < maxIter; ++j) {
938e6a796c3SToby Isaac       PetscReal s = 0.0, delta, f, fp;
939e6a796c3SToby Isaac       PetscInt  i;
940e6a796c3SToby Isaac 
941e6a796c3SToby Isaac       for (i = 0; i < k; ++i) s = s + 1.0 / (r - x[i]);
942e6a796c3SToby Isaac       ierr = PetscDTComputeJacobi(a, b, npoints, r, &f);CHKERRQ(ierr);
943e6a796c3SToby Isaac       ierr = PetscDTComputeJacobiDerivative(a, b, npoints, r, 1, &fp);CHKERRQ(ierr);
944e6a796c3SToby Isaac       delta = f / (fp - f * s);
945e6a796c3SToby Isaac       r     = r - delta;
946e6a796c3SToby Isaac       if (PetscAbsReal(delta) < eps) break;
947e6a796c3SToby Isaac     }
948e6a796c3SToby Isaac     x[k] = r;
949e6a796c3SToby Isaac     ierr = PetscDTComputeJacobiDerivative(a, b, npoints, x[k], 1, &dP);CHKERRQ(ierr);
950e6a796c3SToby Isaac     w[k] = a6 / (1.0 - PetscSqr(x[k])) / PetscSqr(dP);
951e6a796c3SToby Isaac   }
952e6a796c3SToby Isaac   PetscFunctionReturn(0);
953e6a796c3SToby Isaac }
954e6a796c3SToby Isaac 
95594e21283SToby Isaac /* Compute the diagonals of the Jacobi matrix used in Golub & Welsch algorithms for Gauss-Jacobi
956e6a796c3SToby Isaac  * quadrature weight calculations on [-1,1] for exponents (1. + x)^a (1.-x)^b */
957e6a796c3SToby Isaac static PetscErrorCode PetscDTJacobiMatrix_Internal(PetscInt nPoints, PetscReal a, PetscReal b, PetscReal *d, PetscReal *s)
958e6a796c3SToby Isaac {
959e6a796c3SToby Isaac   PetscInt       i;
960e6a796c3SToby Isaac 
961e6a796c3SToby Isaac   PetscFunctionBegin;
962e6a796c3SToby Isaac   for (i = 0; i < nPoints; i++) {
96394e21283SToby Isaac     PetscReal A, B, C;
964e6a796c3SToby Isaac 
96594e21283SToby Isaac     PetscDTJacobiRecurrence_Internal(i+1,a,b,A,B,C);
96694e21283SToby Isaac     d[i] = -A / B;
96794e21283SToby Isaac     if (i) s[i-1] *= C / B;
96894e21283SToby Isaac     if (i < nPoints - 1) s[i] = 1. / B;
969e6a796c3SToby Isaac   }
970e6a796c3SToby Isaac   PetscFunctionReturn(0);
971e6a796c3SToby Isaac }
972e6a796c3SToby Isaac 
973e6a796c3SToby Isaac static PetscErrorCode PetscDTGaussJacobiQuadrature_GolubWelsch_Internal(PetscInt npoints, PetscReal a, PetscReal b, PetscReal *x, PetscReal *w)
974e6a796c3SToby Isaac {
975e6a796c3SToby Isaac   PetscReal mu0;
976e6a796c3SToby Isaac   PetscReal ga, gb, gab;
977e6a796c3SToby Isaac   PetscInt i;
978e6a796c3SToby Isaac   PetscErrorCode ierr;
979e6a796c3SToby Isaac 
980e6a796c3SToby Isaac   PetscFunctionBegin;
981e6a796c3SToby Isaac   ierr = PetscCitationsRegister(GolubWelschCitation, &GolubWelschCite);CHKERRQ(ierr);
982e6a796c3SToby Isaac 
983e6a796c3SToby Isaac #if defined(PETSC_HAVE_TGAMMA)
984e6a796c3SToby Isaac   ga  = PetscTGamma(a + 1);
985e6a796c3SToby Isaac   gb  = PetscTGamma(b + 1);
986e6a796c3SToby Isaac   gab = PetscTGamma(a + b + 2);
987e6a796c3SToby Isaac #else
988e6a796c3SToby Isaac   {
989e6a796c3SToby Isaac     PetscInt ia, ib;
990e6a796c3SToby Isaac 
991e6a796c3SToby Isaac     ia = (PetscInt) a;
992e6a796c3SToby Isaac     ib = (PetscInt) b;
993e6a796c3SToby Isaac     if (ia == a && ib == b && ia + 1 > 0 && ib + 1 > 0 && ia + ib + 2 > 0) { /* All gamma(x) terms are (x-1)! terms */
994e6a796c3SToby Isaac       ierr = PetscDTFactorial(ia, &ga);CHKERRQ(ierr);
995e6a796c3SToby Isaac       ierr = PetscDTFactorial(ib, &gb);CHKERRQ(ierr);
996e6a796c3SToby Isaac       ierr = PetscDTFactorial(ia + ib + 1, &gb);CHKERRQ(ierr);
997e6a796c3SToby Isaac     } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"tgamma() - math routine is unavailable.");
998e6a796c3SToby Isaac   }
999e6a796c3SToby Isaac #endif
1000e6a796c3SToby Isaac   mu0 = PetscPowReal(2.,a + b + 1.) * ga * gb / gab;
1001e6a796c3SToby Isaac 
1002e6a796c3SToby Isaac #if defined(PETSCDTGAUSSIANQUADRATURE_EIG)
1003e6a796c3SToby Isaac   {
1004e6a796c3SToby Isaac     PetscReal *diag, *subdiag;
1005e6a796c3SToby Isaac     PetscScalar *V;
1006e6a796c3SToby Isaac 
1007e6a796c3SToby Isaac     ierr = PetscMalloc2(npoints, &diag, npoints, &subdiag);CHKERRQ(ierr);
1008e6a796c3SToby Isaac     ierr = PetscMalloc1(npoints*npoints, &V);CHKERRQ(ierr);
1009e6a796c3SToby Isaac     ierr = PetscDTJacobiMatrix_Internal(npoints, a, b, diag, subdiag);CHKERRQ(ierr);
1010e6a796c3SToby Isaac     for (i = 0; i < npoints - 1; i++) subdiag[i] = PetscSqrtReal(subdiag[i]);
1011e6a796c3SToby Isaac     ierr = PetscDTSymmetricTridiagonalEigensolve(npoints, diag, subdiag, x, V);CHKERRQ(ierr);
101294e21283SToby Isaac     for (i = 0; i < npoints; i++) w[i] = PetscSqr(PetscRealPart(V[i * npoints])) * mu0;
1013e6a796c3SToby Isaac     ierr = PetscFree(V);CHKERRQ(ierr);
1014e6a796c3SToby Isaac     ierr = PetscFree2(diag, subdiag);CHKERRQ(ierr);
1015e6a796c3SToby Isaac   }
1016e6a796c3SToby Isaac #else
1017e6a796c3SToby Isaac   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "A LAPACK symmetric tridiagonal eigensolver could not be found");
1018e6a796c3SToby Isaac #endif
101994e21283SToby Isaac   { /* As of March 2, 2020, The Sun Performance Library breaks the LAPACK contract for xstegr and xsteqr: the
102094e21283SToby Isaac        eigenvalues are not guaranteed to be in ascending order.  So we heave a passive aggressive sigh and check that
102194e21283SToby Isaac        the eigenvalues are sorted */
102294e21283SToby Isaac     PetscBool sorted;
102394e21283SToby Isaac 
102494e21283SToby Isaac     ierr = PetscSortedReal(npoints, x, &sorted);CHKERRQ(ierr);
102594e21283SToby Isaac     if (!sorted) {
102694e21283SToby Isaac       PetscInt *order, i;
102794e21283SToby Isaac       PetscReal *tmp;
102894e21283SToby Isaac 
102994e21283SToby Isaac       ierr = PetscMalloc2(npoints, &order, npoints, &tmp);CHKERRQ(ierr);
103094e21283SToby Isaac       for (i = 0; i < npoints; i++) order[i] = i;
103194e21283SToby Isaac       ierr = PetscSortRealWithPermutation(npoints, x, order);CHKERRQ(ierr);
103294e21283SToby Isaac       ierr = PetscArraycpy(tmp, x, npoints);CHKERRQ(ierr);
103394e21283SToby Isaac       for (i = 0; i < npoints; i++) x[i] = tmp[order[i]];
103494e21283SToby Isaac       ierr = PetscArraycpy(tmp, w, npoints);CHKERRQ(ierr);
103594e21283SToby Isaac       for (i = 0; i < npoints; i++) w[i] = tmp[order[i]];
103694e21283SToby Isaac       ierr = PetscFree2(order, tmp);CHKERRQ(ierr);
103794e21283SToby Isaac     }
103894e21283SToby Isaac   }
1039e6a796c3SToby Isaac   PetscFunctionReturn(0);
1040e6a796c3SToby Isaac }
1041e6a796c3SToby Isaac 
1042e6a796c3SToby Isaac static PetscErrorCode PetscDTGaussJacobiQuadrature_Internal(PetscInt npoints,PetscReal alpha, PetscReal beta, PetscReal x[], PetscReal w[], PetscBool newton)
1043e6a796c3SToby Isaac {
1044e6a796c3SToby Isaac   PetscErrorCode ierr;
1045e6a796c3SToby Isaac 
1046e6a796c3SToby Isaac   PetscFunctionBegin;
1047e6a796c3SToby Isaac   if (npoints < 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Number of points must be positive");
1048e6a796c3SToby Isaac   /* If asking for a 1D Lobatto point, just return the non-Lobatto 1D point */
1049e6a796c3SToby Isaac   if (alpha <= -1.) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"alpha must be > -1.");
1050e6a796c3SToby Isaac   if (beta <= -1.) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"beta must be > -1.");
1051e6a796c3SToby Isaac 
1052e6a796c3SToby Isaac   if (newton) {
1053e6a796c3SToby Isaac     ierr = PetscDTGaussJacobiQuadrature_Newton_Internal(npoints, alpha, beta, x, w);CHKERRQ(ierr);
1054e6a796c3SToby Isaac   } else {
1055e6a796c3SToby Isaac     ierr = PetscDTGaussJacobiQuadrature_GolubWelsch_Internal(npoints, alpha, beta, x, w);CHKERRQ(ierr);
1056e6a796c3SToby Isaac   }
1057e6a796c3SToby Isaac   if (alpha == beta) { /* symmetrize */
1058e6a796c3SToby Isaac     PetscInt i;
1059e6a796c3SToby Isaac     for (i = 0; i < (npoints + 1) / 2; i++) {
1060e6a796c3SToby Isaac       PetscInt  j  = npoints - 1 - i;
1061e6a796c3SToby Isaac       PetscReal xi = x[i];
1062e6a796c3SToby Isaac       PetscReal xj = x[j];
1063e6a796c3SToby Isaac       PetscReal wi = w[i];
1064e6a796c3SToby Isaac       PetscReal wj = w[j];
1065e6a796c3SToby Isaac 
1066e6a796c3SToby Isaac       x[i] = (xi - xj) / 2.;
1067e6a796c3SToby Isaac       x[j] = (xj - xi) / 2.;
1068e6a796c3SToby Isaac       w[i] = w[j] = (wi + wj) / 2.;
1069e6a796c3SToby Isaac     }
1070e6a796c3SToby Isaac   }
1071e6a796c3SToby Isaac   PetscFunctionReturn(0);
1072e6a796c3SToby Isaac }
1073e6a796c3SToby Isaac 
107494e21283SToby Isaac /*@
107594e21283SToby Isaac   PetscDTGaussJacobiQuadrature - quadrature for the interval [a, b] with the weight function
107694e21283SToby Isaac   $(x-a)^\alpha (x-b)^\beta$.
107794e21283SToby Isaac 
107894e21283SToby Isaac   Not collective
107994e21283SToby Isaac 
108094e21283SToby Isaac   Input Parameters:
108194e21283SToby Isaac + npoints - the number of points in the quadrature rule
108294e21283SToby Isaac . a - the left endpoint of the interval
108394e21283SToby Isaac . b - the right endpoint of the interval
108494e21283SToby Isaac . alpha - the left exponent
108594e21283SToby Isaac - beta - the right exponent
108694e21283SToby Isaac 
108794e21283SToby Isaac   Output Parameters:
108894e21283SToby Isaac + x - array of length npoints, the locations of the quadrature points
108994e21283SToby Isaac - w - array of length npoints, the weights of the quadrature points
109094e21283SToby Isaac 
109194e21283SToby Isaac   Level: intermediate
109294e21283SToby Isaac 
109394e21283SToby Isaac   Note: this quadrature rule is exact for polynomials up to degree 2*npoints - 1.
109494e21283SToby Isaac @*/
109594e21283SToby Isaac PetscErrorCode PetscDTGaussJacobiQuadrature(PetscInt npoints,PetscReal a, PetscReal b, PetscReal alpha, PetscReal beta, PetscReal x[], PetscReal w[])
1096e6a796c3SToby Isaac {
109794e21283SToby Isaac   PetscInt       i;
1098e6a796c3SToby Isaac   PetscErrorCode ierr;
1099e6a796c3SToby Isaac 
1100e6a796c3SToby Isaac   PetscFunctionBegin;
110194e21283SToby Isaac   ierr = PetscDTGaussJacobiQuadrature_Internal(npoints, alpha, beta, x, w, PetscDTGaussQuadratureNewton_Internal);CHKERRQ(ierr);
110294e21283SToby Isaac   if (a != -1. || b != 1.) { /* shift */
110394e21283SToby Isaac     for (i = 0; i < npoints; i++) {
110494e21283SToby Isaac       x[i] = (x[i] + 1.) * ((b - a) / 2.) + a;
110594e21283SToby Isaac       w[i] *= (b - a) / 2.;
110694e21283SToby Isaac     }
110794e21283SToby Isaac   }
1108e6a796c3SToby Isaac   PetscFunctionReturn(0);
1109e6a796c3SToby Isaac }
1110e6a796c3SToby Isaac 
1111e6a796c3SToby Isaac static PetscErrorCode PetscDTGaussLobattoJacobiQuadrature_Internal(PetscInt npoints,PetscReal alpha, PetscReal beta, PetscReal x[], PetscReal w[], PetscBool newton)
1112e6a796c3SToby Isaac {
1113e6a796c3SToby Isaac   PetscInt       i;
1114e6a796c3SToby Isaac   PetscErrorCode ierr;
1115e6a796c3SToby Isaac 
1116e6a796c3SToby Isaac   PetscFunctionBegin;
1117e6a796c3SToby Isaac   if (npoints < 2) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Number of points must be positive");
1118e6a796c3SToby Isaac   /* If asking for a 1D Lobatto point, just return the non-Lobatto 1D point */
1119e6a796c3SToby Isaac   if (alpha <= -1.) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"alpha must be > -1.");
1120e6a796c3SToby Isaac   if (beta <= -1.) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"beta must be > -1.");
1121e6a796c3SToby Isaac 
1122e6a796c3SToby Isaac   x[0] = -1.;
1123e6a796c3SToby Isaac   x[npoints-1] = 1.;
112494e21283SToby Isaac   if (npoints > 2) {
112594e21283SToby Isaac     ierr = PetscDTGaussJacobiQuadrature_Internal(npoints-2, alpha+1., beta+1., &x[1], &w[1], newton);CHKERRQ(ierr);
112694e21283SToby Isaac   }
1127e6a796c3SToby Isaac   for (i = 1; i < npoints - 1; i++) {
1128e6a796c3SToby Isaac     w[i] /= (1. - x[i]*x[i]);
1129e6a796c3SToby Isaac   }
1130e6a796c3SToby Isaac   ierr = PetscDTGaussLobattoJacobiEndweights_Internal(npoints, alpha, beta, &w[0], &w[npoints-1]);CHKERRQ(ierr);
1131e6a796c3SToby Isaac   PetscFunctionReturn(0);
1132e6a796c3SToby Isaac }
1133e6a796c3SToby Isaac 
113437045ce4SJed Brown /*@
113594e21283SToby Isaac   PetscDTGaussLobattoJacobiQuadrature - quadrature for the interval [a, b] with the weight function
113694e21283SToby Isaac   $(x-a)^\alpha (x-b)^\beta$, with endpoints a and b included as quadrature points.
113794e21283SToby Isaac 
113894e21283SToby Isaac   Not collective
113994e21283SToby Isaac 
114094e21283SToby Isaac   Input Parameters:
114194e21283SToby Isaac + npoints - the number of points in the quadrature rule
114294e21283SToby Isaac . a - the left endpoint of the interval
114394e21283SToby Isaac . b - the right endpoint of the interval
114494e21283SToby Isaac . alpha - the left exponent
114594e21283SToby Isaac - beta - the right exponent
114694e21283SToby Isaac 
114794e21283SToby Isaac   Output Parameters:
114894e21283SToby Isaac + x - array of length npoints, the locations of the quadrature points
114994e21283SToby Isaac - w - array of length npoints, the weights of the quadrature points
115094e21283SToby Isaac 
115194e21283SToby Isaac   Level: intermediate
115294e21283SToby Isaac 
115394e21283SToby Isaac   Note: this quadrature rule is exact for polynomials up to degree 2*npoints - 3.
115494e21283SToby Isaac @*/
115594e21283SToby Isaac PetscErrorCode PetscDTGaussLobattoJacobiQuadrature(PetscInt npoints,PetscReal a, PetscReal b, PetscReal alpha, PetscReal beta, PetscReal x[], PetscReal w[])
115694e21283SToby Isaac {
115794e21283SToby Isaac   PetscInt       i;
115894e21283SToby Isaac   PetscErrorCode ierr;
115994e21283SToby Isaac 
116094e21283SToby Isaac   PetscFunctionBegin;
116194e21283SToby Isaac   ierr = PetscDTGaussLobattoJacobiQuadrature_Internal(npoints, alpha, beta, x, w, PetscDTGaussQuadratureNewton_Internal);CHKERRQ(ierr);
116294e21283SToby Isaac   if (a != -1. || b != 1.) { /* shift */
116394e21283SToby Isaac     for (i = 0; i < npoints; i++) {
116494e21283SToby Isaac       x[i] = (x[i] + 1.) * ((b - a) / 2.) + a;
116594e21283SToby Isaac       w[i] *= (b - a) / 2.;
116694e21283SToby Isaac     }
116794e21283SToby Isaac   }
116894e21283SToby Isaac   PetscFunctionReturn(0);
116994e21283SToby Isaac }
117094e21283SToby Isaac 
117194e21283SToby Isaac /*@
1172e6a796c3SToby Isaac    PetscDTGaussQuadrature - create Gauss-Legendre quadrature
117337045ce4SJed Brown 
117437045ce4SJed Brown    Not Collective
117537045ce4SJed Brown 
117637045ce4SJed Brown    Input Arguments:
117737045ce4SJed Brown +  npoints - number of points
117837045ce4SJed Brown .  a - left end of interval (often-1)
117937045ce4SJed Brown -  b - right end of interval (often +1)
118037045ce4SJed Brown 
118137045ce4SJed Brown    Output Arguments:
118237045ce4SJed Brown +  x - quadrature points
118337045ce4SJed Brown -  w - quadrature weights
118437045ce4SJed Brown 
118537045ce4SJed Brown    Level: intermediate
118637045ce4SJed Brown 
118737045ce4SJed Brown    References:
118896a0c994SBarry Smith .   1. - Golub and Welsch, Calculation of Quadrature Rules, Math. Comp. 23(106), 1969.
118937045ce4SJed Brown 
119037045ce4SJed Brown .seealso: PetscDTLegendreEval()
119137045ce4SJed Brown @*/
119237045ce4SJed Brown PetscErrorCode PetscDTGaussQuadrature(PetscInt npoints,PetscReal a,PetscReal b,PetscReal *x,PetscReal *w)
119337045ce4SJed Brown {
119437045ce4SJed Brown   PetscInt       i;
1195e6a796c3SToby Isaac   PetscErrorCode ierr;
119637045ce4SJed Brown 
119737045ce4SJed Brown   PetscFunctionBegin;
119894e21283SToby Isaac   ierr = PetscDTGaussJacobiQuadrature_Internal(npoints, 0., 0., x, w, PetscDTGaussQuadratureNewton_Internal);CHKERRQ(ierr);
119994e21283SToby Isaac   if (a != -1. || b != 1.) { /* shift */
120037045ce4SJed Brown     for (i = 0; i < npoints; i++) {
1201e6a796c3SToby Isaac       x[i] = (x[i] + 1.) * ((b - a) / 2.) + a;
1202e6a796c3SToby Isaac       w[i] *= (b - a) / 2.;
120337045ce4SJed Brown     }
120437045ce4SJed Brown   }
120537045ce4SJed Brown   PetscFunctionReturn(0);
120637045ce4SJed Brown }
1207194825f6SJed Brown 
12088272889dSSatish Balay /*@C
12098272889dSSatish Balay    PetscDTGaussLobattoLegendreQuadrature - creates a set of the locations and weights of the Gauss-Lobatto-Legendre
12108272889dSSatish Balay                       nodes of a given size on the domain [-1,1]
12118272889dSSatish Balay 
12128272889dSSatish Balay    Not Collective
12138272889dSSatish Balay 
12148272889dSSatish Balay    Input Parameter:
12158272889dSSatish Balay +  n - number of grid nodes
1216f2e8fe4dShannah_mairs -  type - PETSCGAUSSLOBATTOLEGENDRE_VIA_LINEAR_ALGEBRA or PETSCGAUSSLOBATTOLEGENDRE_VIA_NEWTON
12178272889dSSatish Balay 
12188272889dSSatish Balay    Output Arguments:
12198272889dSSatish Balay +  x - quadrature points
12208272889dSSatish Balay -  w - quadrature weights
12218272889dSSatish Balay 
12228272889dSSatish Balay    Notes:
12238272889dSSatish Balay     For n > 30  the Newton approach computes duplicate (incorrect) values for some nodes because the initial guess is apparently not
12248272889dSSatish Balay           close enough to the desired solution
12258272889dSSatish Balay 
12268272889dSSatish Balay    These are useful for implementing spectral methods based on Gauss-Lobatto-Legendre (GLL) nodes
12278272889dSSatish Balay 
1228a8d69d7bSBarry 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
12298272889dSSatish Balay 
12308272889dSSatish Balay    Level: intermediate
12318272889dSSatish Balay 
12328272889dSSatish Balay .seealso: PetscDTGaussQuadrature()
12338272889dSSatish Balay 
12348272889dSSatish Balay @*/
1235916e780bShannah_mairs PetscErrorCode PetscDTGaussLobattoLegendreQuadrature(PetscInt npoints,PetscGaussLobattoLegendreCreateType type,PetscReal *x,PetscReal *w)
12368272889dSSatish Balay {
1237e6a796c3SToby Isaac   PetscBool      newton;
12388272889dSSatish Balay   PetscErrorCode ierr;
12398272889dSSatish Balay 
12408272889dSSatish Balay   PetscFunctionBegin;
12418272889dSSatish Balay   if (npoints < 2) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Must provide at least 2 grid points per element");
124294e21283SToby Isaac   newton = (PetscBool) (type == PETSCGAUSSLOBATTOLEGENDRE_VIA_NEWTON);
1243e6a796c3SToby Isaac   ierr = PetscDTGaussLobattoJacobiQuadrature_Internal(npoints, 0., 0., x, w, newton);CHKERRQ(ierr);
12448272889dSSatish Balay   PetscFunctionReturn(0);
12458272889dSSatish Balay }
12468272889dSSatish Balay 
1247744bafbcSMatthew G. Knepley /*@
1248744bafbcSMatthew G. Knepley   PetscDTGaussTensorQuadrature - creates a tensor-product Gauss quadrature
1249744bafbcSMatthew G. Knepley 
1250744bafbcSMatthew G. Knepley   Not Collective
1251744bafbcSMatthew G. Knepley 
1252744bafbcSMatthew G. Knepley   Input Arguments:
1253744bafbcSMatthew G. Knepley + dim     - The spatial dimension
1254a6b92713SMatthew G. Knepley . Nc      - The number of components
1255744bafbcSMatthew G. Knepley . npoints - number of points in one dimension
1256744bafbcSMatthew G. Knepley . a       - left end of interval (often-1)
1257744bafbcSMatthew G. Knepley - b       - right end of interval (often +1)
1258744bafbcSMatthew G. Knepley 
1259744bafbcSMatthew G. Knepley   Output Argument:
1260744bafbcSMatthew G. Knepley . q - A PetscQuadrature object
1261744bafbcSMatthew G. Knepley 
1262744bafbcSMatthew G. Knepley   Level: intermediate
1263744bafbcSMatthew G. Knepley 
1264744bafbcSMatthew G. Knepley .seealso: PetscDTGaussQuadrature(), PetscDTLegendreEval()
1265744bafbcSMatthew G. Knepley @*/
1266a6b92713SMatthew G. Knepley PetscErrorCode PetscDTGaussTensorQuadrature(PetscInt dim, PetscInt Nc, PetscInt npoints, PetscReal a, PetscReal b, PetscQuadrature *q)
1267744bafbcSMatthew G. Knepley {
1268a6b92713SMatthew G. Knepley   PetscInt       totpoints = dim > 1 ? dim > 2 ? npoints*PetscSqr(npoints) : PetscSqr(npoints) : npoints, i, j, k, c;
1269744bafbcSMatthew G. Knepley   PetscReal     *x, *w, *xw, *ww;
1270744bafbcSMatthew G. Knepley   PetscErrorCode ierr;
1271744bafbcSMatthew G. Knepley 
1272744bafbcSMatthew G. Knepley   PetscFunctionBegin;
1273744bafbcSMatthew G. Knepley   ierr = PetscMalloc1(totpoints*dim,&x);CHKERRQ(ierr);
1274a6b92713SMatthew G. Knepley   ierr = PetscMalloc1(totpoints*Nc,&w);CHKERRQ(ierr);
1275744bafbcSMatthew G. Knepley   /* Set up the Golub-Welsch system */
1276744bafbcSMatthew G. Knepley   switch (dim) {
1277744bafbcSMatthew G. Knepley   case 0:
1278744bafbcSMatthew G. Knepley     ierr = PetscFree(x);CHKERRQ(ierr);
1279744bafbcSMatthew G. Knepley     ierr = PetscFree(w);CHKERRQ(ierr);
1280744bafbcSMatthew G. Knepley     ierr = PetscMalloc1(1, &x);CHKERRQ(ierr);
1281a6b92713SMatthew G. Knepley     ierr = PetscMalloc1(Nc, &w);CHKERRQ(ierr);
1282744bafbcSMatthew G. Knepley     x[0] = 0.0;
1283a6b92713SMatthew G. Knepley     for (c = 0; c < Nc; ++c) w[c] = 1.0;
1284744bafbcSMatthew G. Knepley     break;
1285744bafbcSMatthew G. Knepley   case 1:
1286a6b92713SMatthew G. Knepley     ierr = PetscMalloc1(npoints,&ww);CHKERRQ(ierr);
1287a6b92713SMatthew G. Knepley     ierr = PetscDTGaussQuadrature(npoints, a, b, x, ww);CHKERRQ(ierr);
1288a6b92713SMatthew G. Knepley     for (i = 0; i < npoints; ++i) for (c = 0; c < Nc; ++c) w[i*Nc+c] = ww[i];
1289a6b92713SMatthew G. Knepley     ierr = PetscFree(ww);CHKERRQ(ierr);
1290744bafbcSMatthew G. Knepley     break;
1291744bafbcSMatthew G. Knepley   case 2:
1292744bafbcSMatthew G. Knepley     ierr = PetscMalloc2(npoints,&xw,npoints,&ww);CHKERRQ(ierr);
1293744bafbcSMatthew G. Knepley     ierr = PetscDTGaussQuadrature(npoints, a, b, xw, ww);CHKERRQ(ierr);
1294744bafbcSMatthew G. Knepley     for (i = 0; i < npoints; ++i) {
1295744bafbcSMatthew G. Knepley       for (j = 0; j < npoints; ++j) {
1296744bafbcSMatthew G. Knepley         x[(i*npoints+j)*dim+0] = xw[i];
1297744bafbcSMatthew G. Knepley         x[(i*npoints+j)*dim+1] = xw[j];
1298a6b92713SMatthew G. Knepley         for (c = 0; c < Nc; ++c) w[(i*npoints+j)*Nc+c] = ww[i] * ww[j];
1299744bafbcSMatthew G. Knepley       }
1300744bafbcSMatthew G. Knepley     }
1301744bafbcSMatthew G. Knepley     ierr = PetscFree2(xw,ww);CHKERRQ(ierr);
1302744bafbcSMatthew G. Knepley     break;
1303744bafbcSMatthew G. Knepley   case 3:
1304744bafbcSMatthew G. Knepley     ierr = PetscMalloc2(npoints,&xw,npoints,&ww);CHKERRQ(ierr);
1305744bafbcSMatthew G. Knepley     ierr = PetscDTGaussQuadrature(npoints, a, b, xw, ww);CHKERRQ(ierr);
1306744bafbcSMatthew G. Knepley     for (i = 0; i < npoints; ++i) {
1307744bafbcSMatthew G. Knepley       for (j = 0; j < npoints; ++j) {
1308744bafbcSMatthew G. Knepley         for (k = 0; k < npoints; ++k) {
1309744bafbcSMatthew G. Knepley           x[((i*npoints+j)*npoints+k)*dim+0] = xw[i];
1310744bafbcSMatthew G. Knepley           x[((i*npoints+j)*npoints+k)*dim+1] = xw[j];
1311744bafbcSMatthew G. Knepley           x[((i*npoints+j)*npoints+k)*dim+2] = xw[k];
1312a6b92713SMatthew G. Knepley           for (c = 0; c < Nc; ++c) w[((i*npoints+j)*npoints+k)*Nc+c] = ww[i] * ww[j] * ww[k];
1313744bafbcSMatthew G. Knepley         }
1314744bafbcSMatthew G. Knepley       }
1315744bafbcSMatthew G. Knepley     }
1316744bafbcSMatthew G. Knepley     ierr = PetscFree2(xw,ww);CHKERRQ(ierr);
1317744bafbcSMatthew G. Knepley     break;
1318744bafbcSMatthew G. Knepley   default:
1319744bafbcSMatthew G. Knepley     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct quadrature rule for dimension %d", dim);
1320744bafbcSMatthew G. Knepley   }
1321744bafbcSMatthew G. Knepley   ierr = PetscQuadratureCreate(PETSC_COMM_SELF, q);CHKERRQ(ierr);
13222f5fb066SToby Isaac   ierr = PetscQuadratureSetOrder(*q, 2*npoints-1);CHKERRQ(ierr);
1323a6b92713SMatthew G. Knepley   ierr = PetscQuadratureSetData(*q, dim, Nc, totpoints, x, w);CHKERRQ(ierr);
1324d9bac1caSLisandro Dalcin   ierr = PetscObjectChangeTypeName((PetscObject)*q,"GaussTensor");CHKERRQ(ierr);
1325744bafbcSMatthew G. Knepley   PetscFunctionReturn(0);
1326744bafbcSMatthew G. Knepley }
1327744bafbcSMatthew G. Knepley 
1328494e7359SMatthew G. Knepley /* Maps from [-1,1]^2 to the (-1,1) reference triangle */
1329494e7359SMatthew G. Knepley PETSC_STATIC_INLINE PetscErrorCode PetscDTMapCubeToTetrahedron_Internal(PetscReal x, PetscReal y, PetscReal z, PetscReal *xi, PetscReal *eta, PetscReal *zeta)
1330494e7359SMatthew G. Knepley {
1331494e7359SMatthew G. Knepley   PetscFunctionBegin;
1332494e7359SMatthew G. Knepley   *xi   = 0.25 * (1.0 + x) * (1.0 - y) * (1.0 - z) - 1.0;
1333494e7359SMatthew G. Knepley   *eta  = 0.5  * (1.0 + y) * (1.0 - z) - 1.0;
1334494e7359SMatthew G. Knepley   *zeta = z;
1335494e7359SMatthew G. Knepley   PetscFunctionReturn(0);
1336494e7359SMatthew G. Knepley }
1337494e7359SMatthew G. Knepley 
1338494e7359SMatthew G. Knepley 
1339f5f57ec0SBarry Smith /*@
1340e6a796c3SToby Isaac   PetscDTStroudConicalQuadrature - create Stroud conical quadrature for a simplex
1341494e7359SMatthew G. Knepley 
1342494e7359SMatthew G. Knepley   Not Collective
1343494e7359SMatthew G. Knepley 
1344494e7359SMatthew G. Knepley   Input Arguments:
1345494e7359SMatthew G. Knepley + dim     - The simplex dimension
1346a6b92713SMatthew G. Knepley . Nc      - The number of components
1347dcce0ee2SMatthew G. Knepley . npoints - The number of points in one dimension
1348494e7359SMatthew G. Knepley . a       - left end of interval (often-1)
1349494e7359SMatthew G. Knepley - b       - right end of interval (often +1)
1350494e7359SMatthew G. Knepley 
1351744bafbcSMatthew G. Knepley   Output Argument:
1352552aa4f7SMatthew G. Knepley . q - A PetscQuadrature object
1353494e7359SMatthew G. Knepley 
1354494e7359SMatthew G. Knepley   Level: intermediate
1355494e7359SMatthew G. Knepley 
1356494e7359SMatthew G. Knepley   References:
135796a0c994SBarry Smith .  1. - Karniadakis and Sherwin.  FIAT
1358494e7359SMatthew G. Knepley 
1359e6a796c3SToby Isaac   Note: For dim == 1, this is Gauss-Legendre quadrature
1360e6a796c3SToby Isaac 
1361744bafbcSMatthew G. Knepley .seealso: PetscDTGaussTensorQuadrature(), PetscDTGaussQuadrature()
1362494e7359SMatthew G. Knepley @*/
1363e6a796c3SToby Isaac PetscErrorCode PetscDTStroudConicalQuadrature(PetscInt dim, PetscInt Nc, PetscInt npoints, PetscReal a, PetscReal b, PetscQuadrature *q)
1364494e7359SMatthew G. Knepley {
1365dcce0ee2SMatthew G. Knepley   PetscInt       totpoints = dim > 1 ? dim > 2 ? npoints*PetscSqr(npoints) : PetscSqr(npoints) : npoints;
1366494e7359SMatthew G. Knepley   PetscReal     *px, *wx, *py, *wy, *pz, *wz, *x, *w;
1367e6a796c3SToby Isaac   PetscInt       i, j, k, c; PetscErrorCode ierr;
1368494e7359SMatthew G. Knepley 
1369494e7359SMatthew G. Knepley   PetscFunctionBegin;
1370494e7359SMatthew G. Knepley   if ((a != -1.0) || (b != 1.0)) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must use default internal right now");
1371dcce0ee2SMatthew G. Knepley   ierr = PetscMalloc1(totpoints*dim, &x);CHKERRQ(ierr);
1372dcce0ee2SMatthew G. Knepley   ierr = PetscMalloc1(totpoints*Nc, &w);CHKERRQ(ierr);
1373494e7359SMatthew G. Knepley   switch (dim) {
1374707aa5c5SMatthew G. Knepley   case 0:
1375707aa5c5SMatthew G. Knepley     ierr = PetscFree(x);CHKERRQ(ierr);
1376707aa5c5SMatthew G. Knepley     ierr = PetscFree(w);CHKERRQ(ierr);
1377785e854fSJed Brown     ierr = PetscMalloc1(1, &x);CHKERRQ(ierr);
1378a6b92713SMatthew G. Knepley     ierr = PetscMalloc1(Nc, &w);CHKERRQ(ierr);
1379707aa5c5SMatthew G. Knepley     x[0] = 0.0;
1380a6b92713SMatthew G. Knepley     for (c = 0; c < Nc; ++c) w[c] = 1.0;
1381707aa5c5SMatthew G. Knepley     break;
1382494e7359SMatthew G. Knepley   case 1:
1383dcce0ee2SMatthew G. Knepley     ierr = PetscMalloc1(npoints,&wx);CHKERRQ(ierr);
138494e21283SToby Isaac     ierr = PetscDTGaussJacobiQuadrature(npoints, -1., 1., 0.0, 0.0, x, wx);CHKERRQ(ierr);
1385dcce0ee2SMatthew G. Knepley     for (i = 0; i < npoints; ++i) for (c = 0; c < Nc; ++c) w[i*Nc+c] = wx[i];
1386a6b92713SMatthew G. Knepley     ierr = PetscFree(wx);CHKERRQ(ierr);
1387494e7359SMatthew G. Knepley     break;
1388494e7359SMatthew G. Knepley   case 2:
1389dcce0ee2SMatthew G. Knepley     ierr = PetscMalloc4(npoints,&px,npoints,&wx,npoints,&py,npoints,&wy);CHKERRQ(ierr);
139094e21283SToby Isaac     ierr = PetscDTGaussJacobiQuadrature(npoints, -1., 1., 0.0, 0.0, px, wx);CHKERRQ(ierr);
139194e21283SToby Isaac     ierr = PetscDTGaussJacobiQuadrature(npoints, -1., 1., 1.0, 0.0, py, wy);CHKERRQ(ierr);
1392dcce0ee2SMatthew G. Knepley     for (i = 0; i < npoints; ++i) {
1393dcce0ee2SMatthew G. Knepley       for (j = 0; j < npoints; ++j) {
1394dcce0ee2SMatthew G. Knepley         ierr = PetscDTMapSquareToTriangle_Internal(px[i], py[j], &x[(i*npoints+j)*2+0], &x[(i*npoints+j)*2+1]);CHKERRQ(ierr);
1395dcce0ee2SMatthew G. Knepley         for (c = 0; c < Nc; ++c) w[(i*npoints+j)*Nc+c] = 0.5 * wx[i] * wy[j];
1396494e7359SMatthew G. Knepley       }
1397494e7359SMatthew G. Knepley     }
1398494e7359SMatthew G. Knepley     ierr = PetscFree4(px,wx,py,wy);CHKERRQ(ierr);
1399494e7359SMatthew G. Knepley     break;
1400494e7359SMatthew G. Knepley   case 3:
1401dcce0ee2SMatthew G. Knepley     ierr = PetscMalloc6(npoints,&px,npoints,&wx,npoints,&py,npoints,&wy,npoints,&pz,npoints,&wz);CHKERRQ(ierr);
140294e21283SToby Isaac     ierr = PetscDTGaussJacobiQuadrature(npoints, -1., 1., 0.0, 0.0, px, wx);CHKERRQ(ierr);
140394e21283SToby Isaac     ierr = PetscDTGaussJacobiQuadrature(npoints, -1., 1., 1.0, 0.0, py, wy);CHKERRQ(ierr);
140494e21283SToby Isaac     ierr = PetscDTGaussJacobiQuadrature(npoints, -1., 1., 2.0, 0.0, pz, wz);CHKERRQ(ierr);
1405dcce0ee2SMatthew G. Knepley     for (i = 0; i < npoints; ++i) {
1406dcce0ee2SMatthew G. Knepley       for (j = 0; j < npoints; ++j) {
1407dcce0ee2SMatthew G. Knepley         for (k = 0; k < npoints; ++k) {
1408dcce0ee2SMatthew 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);
1409dcce0ee2SMatthew G. Knepley           for (c = 0; c < Nc; ++c) w[((i*npoints+j)*npoints+k)*Nc+c] = 0.125 * wx[i] * wy[j] * wz[k];
1410494e7359SMatthew G. Knepley         }
1411494e7359SMatthew G. Knepley       }
1412494e7359SMatthew G. Knepley     }
1413494e7359SMatthew G. Knepley     ierr = PetscFree6(px,wx,py,wy,pz,wz);CHKERRQ(ierr);
1414494e7359SMatthew G. Knepley     break;
1415494e7359SMatthew G. Knepley   default:
1416494e7359SMatthew G. Knepley     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct quadrature rule for dimension %d", dim);
1417494e7359SMatthew G. Knepley   }
141821454ff5SMatthew G. Knepley   ierr = PetscQuadratureCreate(PETSC_COMM_SELF, q);CHKERRQ(ierr);
14192f5fb066SToby Isaac   ierr = PetscQuadratureSetOrder(*q, 2*npoints-1);CHKERRQ(ierr);
1420dcce0ee2SMatthew G. Knepley   ierr = PetscQuadratureSetData(*q, dim, Nc, totpoints, x, w);CHKERRQ(ierr);
1421d9bac1caSLisandro Dalcin   ierr = PetscObjectChangeTypeName((PetscObject)*q,"GaussJacobi");CHKERRQ(ierr);
1422494e7359SMatthew G. Knepley   PetscFunctionReturn(0);
1423494e7359SMatthew G. Knepley }
1424494e7359SMatthew G. Knepley 
1425f5f57ec0SBarry Smith /*@
1426b3c0f97bSTom Klotz   PetscDTTanhSinhTensorQuadrature - create tanh-sinh quadrature for a tensor product cell
1427b3c0f97bSTom Klotz 
1428b3c0f97bSTom Klotz   Not Collective
1429b3c0f97bSTom Klotz 
1430b3c0f97bSTom Klotz   Input Arguments:
1431b3c0f97bSTom Klotz + dim   - The cell dimension
1432b3c0f97bSTom Klotz . level - The number of points in one dimension, 2^l
1433b3c0f97bSTom Klotz . a     - left end of interval (often-1)
1434b3c0f97bSTom Klotz - b     - right end of interval (often +1)
1435b3c0f97bSTom Klotz 
1436b3c0f97bSTom Klotz   Output Argument:
1437b3c0f97bSTom Klotz . q - A PetscQuadrature object
1438b3c0f97bSTom Klotz 
1439b3c0f97bSTom Klotz   Level: intermediate
1440b3c0f97bSTom Klotz 
1441b3c0f97bSTom Klotz .seealso: PetscDTGaussTensorQuadrature()
1442b3c0f97bSTom Klotz @*/
1443b3c0f97bSTom Klotz PetscErrorCode PetscDTTanhSinhTensorQuadrature(PetscInt dim, PetscInt level, PetscReal a, PetscReal b, PetscQuadrature *q)
1444b3c0f97bSTom Klotz {
1445b3c0f97bSTom Klotz   const PetscInt  p     = 16;                        /* Digits of precision in the evaluation */
1446b3c0f97bSTom Klotz   const PetscReal alpha = (b-a)/2.;                  /* Half-width of the integration interval */
1447b3c0f97bSTom Klotz   const PetscReal beta  = (b+a)/2.;                  /* Center of the integration interval */
1448b3c0f97bSTom Klotz   const PetscReal h     = PetscPowReal(2.0, -level); /* Step size, length between x_k */
1449d84b4d08SMatthew G. Knepley   PetscReal       xk;                                /* Quadrature point x_k on reference domain [-1, 1] */
1450b3c0f97bSTom Klotz   PetscReal       wk    = 0.5*PETSC_PI;              /* Quadrature weight at x_k */
1451b3c0f97bSTom Klotz   PetscReal      *x, *w;
1452b3c0f97bSTom Klotz   PetscInt        K, k, npoints;
1453b3c0f97bSTom Klotz   PetscErrorCode  ierr;
1454b3c0f97bSTom Klotz 
1455b3c0f97bSTom Klotz   PetscFunctionBegin;
1456b3c0f97bSTom Klotz   if (dim > 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Dimension %d not yet implemented", dim);
1457b3c0f97bSTom Klotz   if (!level) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must give a number of significant digits");
1458b3c0f97bSTom Klotz   /* Find K such that the weights are < 32 digits of precision */
1459b3c0f97bSTom Klotz   for (K = 1; PetscAbsReal(PetscLog10Real(wk)) < 2*p; ++K) {
14609add2064SThomas Klotz     wk = 0.5*h*PETSC_PI*PetscCoshReal(K*h)/PetscSqr(PetscCoshReal(0.5*PETSC_PI*PetscSinhReal(K*h)));
1461b3c0f97bSTom Klotz   }
1462b3c0f97bSTom Klotz   ierr = PetscQuadratureCreate(PETSC_COMM_SELF, q);CHKERRQ(ierr);
1463b3c0f97bSTom Klotz   ierr = PetscQuadratureSetOrder(*q, 2*K+1);CHKERRQ(ierr);
1464b3c0f97bSTom Klotz   npoints = 2*K-1;
1465b3c0f97bSTom Klotz   ierr = PetscMalloc1(npoints*dim, &x);CHKERRQ(ierr);
1466b3c0f97bSTom Klotz   ierr = PetscMalloc1(npoints, &w);CHKERRQ(ierr);
1467b3c0f97bSTom Klotz   /* Center term */
1468b3c0f97bSTom Klotz   x[0] = beta;
1469b3c0f97bSTom Klotz   w[0] = 0.5*alpha*PETSC_PI;
1470b3c0f97bSTom Klotz   for (k = 1; k < K; ++k) {
14719add2064SThomas Klotz     wk = 0.5*alpha*h*PETSC_PI*PetscCoshReal(k*h)/PetscSqr(PetscCoshReal(0.5*PETSC_PI*PetscSinhReal(k*h)));
14721118d4bcSLisandro Dalcin     xk = PetscTanhReal(0.5*PETSC_PI*PetscSinhReal(k*h));
1473b3c0f97bSTom Klotz     x[2*k-1] = -alpha*xk+beta;
1474b3c0f97bSTom Klotz     w[2*k-1] = wk;
1475b3c0f97bSTom Klotz     x[2*k+0] =  alpha*xk+beta;
1476b3c0f97bSTom Klotz     w[2*k+0] = wk;
1477b3c0f97bSTom Klotz   }
1478a6b92713SMatthew G. Knepley   ierr = PetscQuadratureSetData(*q, dim, 1, npoints, x, w);CHKERRQ(ierr);
1479b3c0f97bSTom Klotz   PetscFunctionReturn(0);
1480b3c0f97bSTom Klotz }
1481b3c0f97bSTom Klotz 
1482b3c0f97bSTom Klotz PetscErrorCode PetscDTTanhSinhIntegrate(void (*func)(PetscReal, PetscReal *), PetscReal a, PetscReal b, PetscInt digits, PetscReal *sol)
1483b3c0f97bSTom Klotz {
1484b3c0f97bSTom Klotz   const PetscInt  p     = 16;        /* Digits of precision in the evaluation */
1485b3c0f97bSTom Klotz   const PetscReal alpha = (b-a)/2.;  /* Half-width of the integration interval */
1486b3c0f97bSTom Klotz   const PetscReal beta  = (b+a)/2.;  /* Center of the integration interval */
1487b3c0f97bSTom Klotz   PetscReal       h     = 1.0;       /* Step size, length between x_k */
1488b3c0f97bSTom Klotz   PetscInt        l     = 0;         /* Level of refinement, h = 2^{-l} */
1489b3c0f97bSTom Klotz   PetscReal       osum  = 0.0;       /* Integral on last level */
1490b3c0f97bSTom Klotz   PetscReal       psum  = 0.0;       /* Integral on the level before the last level */
1491b3c0f97bSTom Klotz   PetscReal       sum;               /* Integral on current level */
1492446c295cSMatthew G. Knepley   PetscReal       yk;                /* Quadrature point 1 - x_k on reference domain [-1, 1] */
1493b3c0f97bSTom Klotz   PetscReal       lx, rx;            /* Quadrature points to the left and right of 0 on the real domain [a, b] */
1494b3c0f97bSTom Klotz   PetscReal       wk;                /* Quadrature weight at x_k */
1495b3c0f97bSTom Klotz   PetscReal       lval, rval;        /* Terms in the quadature sum to the left and right of 0 */
1496b3c0f97bSTom Klotz   PetscInt        d;                 /* Digits of precision in the integral */
1497b3c0f97bSTom Klotz 
1498b3c0f97bSTom Klotz   PetscFunctionBegin;
1499b3c0f97bSTom Klotz   if (digits <= 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must give a positive number of significant digits");
1500b3c0f97bSTom Klotz   /* Center term */
1501b3c0f97bSTom Klotz   func(beta, &lval);
1502b3c0f97bSTom Klotz   sum = 0.5*alpha*PETSC_PI*lval;
1503b3c0f97bSTom Klotz   /* */
1504b3c0f97bSTom Klotz   do {
1505b3c0f97bSTom Klotz     PetscReal lterm, rterm, maxTerm = 0.0, d1, d2, d3, d4;
1506b3c0f97bSTom Klotz     PetscInt  k = 1;
1507b3c0f97bSTom Klotz 
1508b3c0f97bSTom Klotz     ++l;
1509b3c0f97bSTom Klotz     /* PetscPrintf(PETSC_COMM_SELF, "LEVEL %D sum: %15.15f\n", l, sum); */
1510b3c0f97bSTom Klotz     /* At each level of refinement, h --> h/2 and sum --> sum/2 */
1511b3c0f97bSTom Klotz     psum = osum;
1512b3c0f97bSTom Klotz     osum = sum;
1513b3c0f97bSTom Klotz     h   *= 0.5;
1514b3c0f97bSTom Klotz     sum *= 0.5;
1515b3c0f97bSTom Klotz     do {
15169add2064SThomas Klotz       wk = 0.5*h*PETSC_PI*PetscCoshReal(k*h)/PetscSqr(PetscCoshReal(0.5*PETSC_PI*PetscSinhReal(k*h)));
1517446c295cSMatthew G. Knepley       yk = 1.0/(PetscExpReal(0.5*PETSC_PI*PetscSinhReal(k*h)) * PetscCoshReal(0.5*PETSC_PI*PetscSinhReal(k*h)));
1518446c295cSMatthew G. Knepley       lx = -alpha*(1.0 - yk)+beta;
1519446c295cSMatthew G. Knepley       rx =  alpha*(1.0 - yk)+beta;
1520b3c0f97bSTom Klotz       func(lx, &lval);
1521b3c0f97bSTom Klotz       func(rx, &rval);
1522b3c0f97bSTom Klotz       lterm   = alpha*wk*lval;
1523b3c0f97bSTom Klotz       maxTerm = PetscMax(PetscAbsReal(lterm), maxTerm);
1524b3c0f97bSTom Klotz       sum    += lterm;
1525b3c0f97bSTom Klotz       rterm   = alpha*wk*rval;
1526b3c0f97bSTom Klotz       maxTerm = PetscMax(PetscAbsReal(rterm), maxTerm);
1527b3c0f97bSTom Klotz       sum    += rterm;
1528b3c0f97bSTom Klotz       ++k;
1529b3c0f97bSTom Klotz       /* Only need to evaluate every other point on refined levels */
1530b3c0f97bSTom Klotz       if (l != 1) ++k;
15319add2064SThomas Klotz     } while (PetscAbsReal(PetscLog10Real(wk)) < p); /* Only need to evaluate sum until weights are < 32 digits of precision */
1532b3c0f97bSTom Klotz 
1533b3c0f97bSTom Klotz     d1 = PetscLog10Real(PetscAbsReal(sum - osum));
1534b3c0f97bSTom Klotz     d2 = PetscLog10Real(PetscAbsReal(sum - psum));
1535b3c0f97bSTom Klotz     d3 = PetscLog10Real(maxTerm) - p;
153609d48545SBarry Smith     if (PetscMax(PetscAbsReal(lterm), PetscAbsReal(rterm)) == 0.0) d4 = 0.0;
153709d48545SBarry Smith     else d4 = PetscLog10Real(PetscMax(PetscAbsReal(lterm), PetscAbsReal(rterm)));
1538b3c0f97bSTom Klotz     d  = PetscAbsInt(PetscMin(0, PetscMax(PetscMax(PetscMax(PetscSqr(d1)/d2, 2*d1), d3), d4)));
15399add2064SThomas Klotz   } while (d < digits && l < 12);
1540b3c0f97bSTom Klotz   *sol = sum;
1541e510cb1fSThomas Klotz 
1542b3c0f97bSTom Klotz   PetscFunctionReturn(0);
1543b3c0f97bSTom Klotz }
1544b3c0f97bSTom Klotz 
1545497880caSRichard Tran Mills #if defined(PETSC_HAVE_MPFR)
154629f144ccSMatthew G. Knepley PetscErrorCode PetscDTTanhSinhIntegrateMPFR(void (*func)(PetscReal, PetscReal *), PetscReal a, PetscReal b, PetscInt digits, PetscReal *sol)
154729f144ccSMatthew G. Knepley {
1548e510cb1fSThomas Klotz   const PetscInt  safetyFactor = 2;  /* Calculate abcissa until 2*p digits */
154929f144ccSMatthew G. Knepley   PetscInt        l            = 0;  /* Level of refinement, h = 2^{-l} */
155029f144ccSMatthew G. Knepley   mpfr_t          alpha;             /* Half-width of the integration interval */
155129f144ccSMatthew G. Knepley   mpfr_t          beta;              /* Center of the integration interval */
155229f144ccSMatthew G. Knepley   mpfr_t          h;                 /* Step size, length between x_k */
155329f144ccSMatthew G. Knepley   mpfr_t          osum;              /* Integral on last level */
155429f144ccSMatthew G. Knepley   mpfr_t          psum;              /* Integral on the level before the last level */
155529f144ccSMatthew G. Knepley   mpfr_t          sum;               /* Integral on current level */
155629f144ccSMatthew G. Knepley   mpfr_t          yk;                /* Quadrature point 1 - x_k on reference domain [-1, 1] */
155729f144ccSMatthew G. Knepley   mpfr_t          lx, rx;            /* Quadrature points to the left and right of 0 on the real domain [a, b] */
155829f144ccSMatthew G. Knepley   mpfr_t          wk;                /* Quadrature weight at x_k */
155929f144ccSMatthew G. Knepley   PetscReal       lval, rval;        /* Terms in the quadature sum to the left and right of 0 */
156029f144ccSMatthew G. Knepley   PetscInt        d;                 /* Digits of precision in the integral */
156129f144ccSMatthew G. Knepley   mpfr_t          pi2, kh, msinh, mcosh, maxTerm, curTerm, tmp;
156229f144ccSMatthew G. Knepley 
156329f144ccSMatthew G. Knepley   PetscFunctionBegin;
156429f144ccSMatthew G. Knepley   if (digits <= 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must give a positive number of significant digits");
156529f144ccSMatthew G. Knepley   /* Create high precision storage */
1566c9f744b5SMatthew 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);
156729f144ccSMatthew G. Knepley   /* Initialization */
156829f144ccSMatthew G. Knepley   mpfr_set_d(alpha, 0.5*(b-a), MPFR_RNDN);
156929f144ccSMatthew G. Knepley   mpfr_set_d(beta,  0.5*(b+a), MPFR_RNDN);
157029f144ccSMatthew G. Knepley   mpfr_set_d(osum,  0.0,       MPFR_RNDN);
157129f144ccSMatthew G. Knepley   mpfr_set_d(psum,  0.0,       MPFR_RNDN);
157229f144ccSMatthew G. Knepley   mpfr_set_d(h,     1.0,       MPFR_RNDN);
157329f144ccSMatthew G. Knepley   mpfr_const_pi(pi2, MPFR_RNDN);
157429f144ccSMatthew G. Knepley   mpfr_mul_d(pi2, pi2, 0.5, MPFR_RNDN);
157529f144ccSMatthew G. Knepley   /* Center term */
157629f144ccSMatthew G. Knepley   func(0.5*(b+a), &lval);
157729f144ccSMatthew G. Knepley   mpfr_set(sum, pi2, MPFR_RNDN);
157829f144ccSMatthew G. Knepley   mpfr_mul(sum, sum, alpha, MPFR_RNDN);
157929f144ccSMatthew G. Knepley   mpfr_mul_d(sum, sum, lval, MPFR_RNDN);
158029f144ccSMatthew G. Knepley   /* */
158129f144ccSMatthew G. Knepley   do {
158229f144ccSMatthew G. Knepley     PetscReal d1, d2, d3, d4;
158329f144ccSMatthew G. Knepley     PetscInt  k = 1;
158429f144ccSMatthew G. Knepley 
158529f144ccSMatthew G. Knepley     ++l;
158629f144ccSMatthew G. Knepley     mpfr_set_d(maxTerm, 0.0, MPFR_RNDN);
158729f144ccSMatthew G. Knepley     /* PetscPrintf(PETSC_COMM_SELF, "LEVEL %D sum: %15.15f\n", l, sum); */
158829f144ccSMatthew G. Knepley     /* At each level of refinement, h --> h/2 and sum --> sum/2 */
158929f144ccSMatthew G. Knepley     mpfr_set(psum, osum, MPFR_RNDN);
159029f144ccSMatthew G. Knepley     mpfr_set(osum,  sum, MPFR_RNDN);
159129f144ccSMatthew G. Knepley     mpfr_mul_d(h,   h,   0.5, MPFR_RNDN);
159229f144ccSMatthew G. Knepley     mpfr_mul_d(sum, sum, 0.5, MPFR_RNDN);
159329f144ccSMatthew G. Knepley     do {
159429f144ccSMatthew G. Knepley       mpfr_set_si(kh, k, MPFR_RNDN);
159529f144ccSMatthew G. Knepley       mpfr_mul(kh, kh, h, MPFR_RNDN);
159629f144ccSMatthew G. Knepley       /* Weight */
159729f144ccSMatthew G. Knepley       mpfr_set(wk, h, MPFR_RNDN);
159829f144ccSMatthew G. Knepley       mpfr_sinh_cosh(msinh, mcosh, kh, MPFR_RNDN);
159929f144ccSMatthew G. Knepley       mpfr_mul(msinh, msinh, pi2, MPFR_RNDN);
160029f144ccSMatthew G. Knepley       mpfr_mul(mcosh, mcosh, pi2, MPFR_RNDN);
160129f144ccSMatthew G. Knepley       mpfr_cosh(tmp, msinh, MPFR_RNDN);
160229f144ccSMatthew G. Knepley       mpfr_sqr(tmp, tmp, MPFR_RNDN);
160329f144ccSMatthew G. Knepley       mpfr_mul(wk, wk, mcosh, MPFR_RNDN);
160429f144ccSMatthew G. Knepley       mpfr_div(wk, wk, tmp, MPFR_RNDN);
160529f144ccSMatthew G. Knepley       /* Abscissa */
160629f144ccSMatthew G. Knepley       mpfr_set_d(yk, 1.0, MPFR_RNDZ);
160729f144ccSMatthew G. Knepley       mpfr_cosh(tmp, msinh, MPFR_RNDN);
160829f144ccSMatthew G. Knepley       mpfr_div(yk, yk, tmp, MPFR_RNDZ);
160929f144ccSMatthew G. Knepley       mpfr_exp(tmp, msinh, MPFR_RNDN);
161029f144ccSMatthew G. Knepley       mpfr_div(yk, yk, tmp, MPFR_RNDZ);
161129f144ccSMatthew G. Knepley       /* Quadrature points */
161229f144ccSMatthew G. Knepley       mpfr_sub_d(lx, yk, 1.0, MPFR_RNDZ);
161329f144ccSMatthew G. Knepley       mpfr_mul(lx, lx, alpha, MPFR_RNDU);
161429f144ccSMatthew G. Knepley       mpfr_add(lx, lx, beta, MPFR_RNDU);
161529f144ccSMatthew G. Knepley       mpfr_d_sub(rx, 1.0, yk, MPFR_RNDZ);
161629f144ccSMatthew G. Knepley       mpfr_mul(rx, rx, alpha, MPFR_RNDD);
161729f144ccSMatthew G. Knepley       mpfr_add(rx, rx, beta, MPFR_RNDD);
161829f144ccSMatthew G. Knepley       /* Evaluation */
161929f144ccSMatthew G. Knepley       func(mpfr_get_d(lx, MPFR_RNDU), &lval);
162029f144ccSMatthew G. Knepley       func(mpfr_get_d(rx, MPFR_RNDD), &rval);
162129f144ccSMatthew G. Knepley       /* Update */
162229f144ccSMatthew G. Knepley       mpfr_mul(tmp, wk, alpha, MPFR_RNDN);
162329f144ccSMatthew G. Knepley       mpfr_mul_d(tmp, tmp, lval, MPFR_RNDN);
162429f144ccSMatthew G. Knepley       mpfr_add(sum, sum, tmp, MPFR_RNDN);
162529f144ccSMatthew G. Knepley       mpfr_abs(tmp, tmp, MPFR_RNDN);
162629f144ccSMatthew G. Knepley       mpfr_max(maxTerm, maxTerm, tmp, MPFR_RNDN);
162729f144ccSMatthew G. Knepley       mpfr_set(curTerm, tmp, MPFR_RNDN);
162829f144ccSMatthew G. Knepley       mpfr_mul(tmp, wk, alpha, MPFR_RNDN);
162929f144ccSMatthew G. Knepley       mpfr_mul_d(tmp, tmp, rval, MPFR_RNDN);
163029f144ccSMatthew G. Knepley       mpfr_add(sum, sum, tmp, MPFR_RNDN);
163129f144ccSMatthew G. Knepley       mpfr_abs(tmp, tmp, MPFR_RNDN);
163229f144ccSMatthew G. Knepley       mpfr_max(maxTerm, maxTerm, tmp, MPFR_RNDN);
163329f144ccSMatthew G. Knepley       mpfr_max(curTerm, curTerm, tmp, MPFR_RNDN);
163429f144ccSMatthew G. Knepley       ++k;
163529f144ccSMatthew G. Knepley       /* Only need to evaluate every other point on refined levels */
163629f144ccSMatthew G. Knepley       if (l != 1) ++k;
163729f144ccSMatthew G. Knepley       mpfr_log10(tmp, wk, MPFR_RNDN);
163829f144ccSMatthew G. Knepley       mpfr_abs(tmp, tmp, MPFR_RNDN);
1639c9f744b5SMatthew G. Knepley     } while (mpfr_get_d(tmp, MPFR_RNDN) < safetyFactor*digits); /* Only need to evaluate sum until weights are < 32 digits of precision */
164029f144ccSMatthew G. Knepley     mpfr_sub(tmp, sum, osum, MPFR_RNDN);
164129f144ccSMatthew G. Knepley     mpfr_abs(tmp, tmp, MPFR_RNDN);
164229f144ccSMatthew G. Knepley     mpfr_log10(tmp, tmp, MPFR_RNDN);
164329f144ccSMatthew G. Knepley     d1 = mpfr_get_d(tmp, MPFR_RNDN);
164429f144ccSMatthew G. Knepley     mpfr_sub(tmp, sum, psum, MPFR_RNDN);
164529f144ccSMatthew G. Knepley     mpfr_abs(tmp, tmp, MPFR_RNDN);
164629f144ccSMatthew G. Knepley     mpfr_log10(tmp, tmp, MPFR_RNDN);
164729f144ccSMatthew G. Knepley     d2 = mpfr_get_d(tmp, MPFR_RNDN);
164829f144ccSMatthew G. Knepley     mpfr_log10(tmp, maxTerm, MPFR_RNDN);
1649c9f744b5SMatthew G. Knepley     d3 = mpfr_get_d(tmp, MPFR_RNDN) - digits;
165029f144ccSMatthew G. Knepley     mpfr_log10(tmp, curTerm, MPFR_RNDN);
165129f144ccSMatthew G. Knepley     d4 = mpfr_get_d(tmp, MPFR_RNDN);
165229f144ccSMatthew G. Knepley     d  = PetscAbsInt(PetscMin(0, PetscMax(PetscMax(PetscMax(PetscSqr(d1)/d2, 2*d1), d3), d4)));
1653b0649871SThomas Klotz   } while (d < digits && l < 8);
165429f144ccSMatthew G. Knepley   *sol = mpfr_get_d(sum, MPFR_RNDN);
165529f144ccSMatthew G. Knepley   /* Cleanup */
165629f144ccSMatthew G. Knepley   mpfr_clears(alpha, beta, h, sum, osum, psum, yk, wk, lx, rx, tmp, maxTerm, curTerm, pi2, kh, msinh, mcosh, NULL);
165729f144ccSMatthew G. Knepley   PetscFunctionReturn(0);
165829f144ccSMatthew G. Knepley }
1659d525116cSMatthew G. Knepley #else
1660fbfcfee5SBarry Smith 
1661d525116cSMatthew G. Knepley PetscErrorCode PetscDTTanhSinhIntegrateMPFR(void (*func)(PetscReal, PetscReal *), PetscReal a, PetscReal b, PetscInt digits, PetscReal *sol)
1662d525116cSMatthew G. Knepley {
1663d525116cSMatthew G. Knepley   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "This method will not work without MPFR. Reconfigure using --download-mpfr --download-gmp");
1664d525116cSMatthew G. Knepley }
166529f144ccSMatthew G. Knepley #endif
166629f144ccSMatthew G. Knepley 
1667194825f6SJed Brown /* Overwrites A. Can only handle full-rank problems with m>=n
1668194825f6SJed Brown  * A in column-major format
1669194825f6SJed Brown  * Ainv in row-major format
1670194825f6SJed Brown  * tau has length m
1671194825f6SJed Brown  * worksize must be >= max(1,n)
1672194825f6SJed Brown  */
1673194825f6SJed Brown static PetscErrorCode PetscDTPseudoInverseQR(PetscInt m,PetscInt mstride,PetscInt n,PetscReal *A_in,PetscReal *Ainv_out,PetscScalar *tau,PetscInt worksize,PetscScalar *work)
1674194825f6SJed Brown {
1675194825f6SJed Brown   PetscErrorCode ierr;
1676194825f6SJed Brown   PetscBLASInt   M,N,K,lda,ldb,ldwork,info;
1677194825f6SJed Brown   PetscScalar    *A,*Ainv,*R,*Q,Alpha;
1678194825f6SJed Brown 
1679194825f6SJed Brown   PetscFunctionBegin;
1680194825f6SJed Brown #if defined(PETSC_USE_COMPLEX)
1681194825f6SJed Brown   {
1682194825f6SJed Brown     PetscInt i,j;
1683dcca6d9dSJed Brown     ierr = PetscMalloc2(m*n,&A,m*n,&Ainv);CHKERRQ(ierr);
1684194825f6SJed Brown     for (j=0; j<n; j++) {
1685194825f6SJed Brown       for (i=0; i<m; i++) A[i+m*j] = A_in[i+mstride*j];
1686194825f6SJed Brown     }
1687194825f6SJed Brown     mstride = m;
1688194825f6SJed Brown   }
1689194825f6SJed Brown #else
1690194825f6SJed Brown   A = A_in;
1691194825f6SJed Brown   Ainv = Ainv_out;
1692194825f6SJed Brown #endif
1693194825f6SJed Brown 
1694194825f6SJed Brown   ierr = PetscBLASIntCast(m,&M);CHKERRQ(ierr);
1695194825f6SJed Brown   ierr = PetscBLASIntCast(n,&N);CHKERRQ(ierr);
1696194825f6SJed Brown   ierr = PetscBLASIntCast(mstride,&lda);CHKERRQ(ierr);
1697194825f6SJed Brown   ierr = PetscBLASIntCast(worksize,&ldwork);CHKERRQ(ierr);
1698194825f6SJed Brown   ierr = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr);
1699001a771dSBarry Smith   PetscStackCallBLAS("LAPACKgeqrf",LAPACKgeqrf_(&M,&N,A,&lda,tau,work,&ldwork,&info));
1700194825f6SJed Brown   ierr = PetscFPTrapPop();CHKERRQ(ierr);
1701194825f6SJed Brown   if (info) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"xGEQRF error");
1702194825f6SJed Brown   R = A; /* Upper triangular part of A now contains R, the rest contains the elementary reflectors */
1703194825f6SJed Brown 
1704194825f6SJed Brown   /* Extract an explicit representation of Q */
1705194825f6SJed Brown   Q = Ainv;
1706580bdb30SBarry Smith   ierr = PetscArraycpy(Q,A,mstride*n);CHKERRQ(ierr);
1707194825f6SJed Brown   K = N;                        /* full rank */
1708c964aadfSJose E. Roman   PetscStackCallBLAS("LAPACKorgqr",LAPACKorgqr_(&M,&N,&K,Q,&lda,tau,work,&ldwork,&info));
1709194825f6SJed Brown   if (info) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"xORGQR/xUNGQR error");
1710194825f6SJed Brown 
1711194825f6SJed Brown   /* Compute A^{-T} = (R^{-1} Q^T)^T = Q R^{-T} */
1712194825f6SJed Brown   Alpha = 1.0;
1713194825f6SJed Brown   ldb = lda;
1714001a771dSBarry Smith   PetscStackCallBLAS("BLAStrsm",BLAStrsm_("Right","Upper","ConjugateTranspose","NotUnitTriangular",&M,&N,&Alpha,R,&lda,Q,&ldb));
1715194825f6SJed Brown   /* Ainv is Q, overwritten with inverse */
1716194825f6SJed Brown 
1717194825f6SJed Brown #if defined(PETSC_USE_COMPLEX)
1718194825f6SJed Brown   {
1719194825f6SJed Brown     PetscInt i;
1720194825f6SJed Brown     for (i=0; i<m*n; i++) Ainv_out[i] = PetscRealPart(Ainv[i]);
1721194825f6SJed Brown     ierr = PetscFree2(A,Ainv);CHKERRQ(ierr);
1722194825f6SJed Brown   }
1723194825f6SJed Brown #endif
1724194825f6SJed Brown   PetscFunctionReturn(0);
1725194825f6SJed Brown }
1726194825f6SJed Brown 
1727194825f6SJed Brown /* Computes integral of L_p' over intervals {(x0,x1),(x1,x2),...} */
1728194825f6SJed Brown static PetscErrorCode PetscDTLegendreIntegrate(PetscInt ninterval,const PetscReal *x,PetscInt ndegree,const PetscInt *degrees,PetscBool Transpose,PetscReal *B)
1729194825f6SJed Brown {
1730194825f6SJed Brown   PetscErrorCode ierr;
1731194825f6SJed Brown   PetscReal      *Bv;
1732194825f6SJed Brown   PetscInt       i,j;
1733194825f6SJed Brown 
1734194825f6SJed Brown   PetscFunctionBegin;
1735785e854fSJed Brown   ierr = PetscMalloc1((ninterval+1)*ndegree,&Bv);CHKERRQ(ierr);
1736194825f6SJed Brown   /* Point evaluation of L_p on all the source vertices */
1737194825f6SJed Brown   ierr = PetscDTLegendreEval(ninterval+1,x,ndegree,degrees,Bv,NULL,NULL);CHKERRQ(ierr);
1738194825f6SJed Brown   /* Integral over each interval: \int_a^b L_p' = L_p(b)-L_p(a) */
1739194825f6SJed Brown   for (i=0; i<ninterval; i++) {
1740194825f6SJed Brown     for (j=0; j<ndegree; j++) {
1741194825f6SJed Brown       if (Transpose) B[i+ninterval*j] = Bv[(i+1)*ndegree+j] - Bv[i*ndegree+j];
1742194825f6SJed Brown       else           B[i*ndegree+j]   = Bv[(i+1)*ndegree+j] - Bv[i*ndegree+j];
1743194825f6SJed Brown     }
1744194825f6SJed Brown   }
1745194825f6SJed Brown   ierr = PetscFree(Bv);CHKERRQ(ierr);
1746194825f6SJed Brown   PetscFunctionReturn(0);
1747194825f6SJed Brown }
1748194825f6SJed Brown 
1749194825f6SJed Brown /*@
1750194825f6SJed Brown    PetscDTReconstructPoly - create matrix representing polynomial reconstruction using cell intervals and evaluation at target intervals
1751194825f6SJed Brown 
1752194825f6SJed Brown    Not Collective
1753194825f6SJed Brown 
1754194825f6SJed Brown    Input Arguments:
1755194825f6SJed Brown +  degree - degree of reconstruction polynomial
1756194825f6SJed Brown .  nsource - number of source intervals
1757194825f6SJed Brown .  sourcex - sorted coordinates of source cell boundaries (length nsource+1)
1758194825f6SJed Brown .  ntarget - number of target intervals
1759194825f6SJed Brown -  targetx - sorted coordinates of target cell boundaries (length ntarget+1)
1760194825f6SJed Brown 
1761194825f6SJed Brown    Output Arguments:
1762194825f6SJed Brown .  R - reconstruction matrix, utarget = sum_s R[t*nsource+s] * usource[s]
1763194825f6SJed Brown 
1764194825f6SJed Brown    Level: advanced
1765194825f6SJed Brown 
1766194825f6SJed Brown .seealso: PetscDTLegendreEval()
1767194825f6SJed Brown @*/
1768194825f6SJed Brown PetscErrorCode PetscDTReconstructPoly(PetscInt degree,PetscInt nsource,const PetscReal *sourcex,PetscInt ntarget,const PetscReal *targetx,PetscReal *R)
1769194825f6SJed Brown {
1770194825f6SJed Brown   PetscErrorCode ierr;
1771194825f6SJed Brown   PetscInt       i,j,k,*bdegrees,worksize;
1772194825f6SJed Brown   PetscReal      xmin,xmax,center,hscale,*sourcey,*targety,*Bsource,*Bsinv,*Btarget;
1773194825f6SJed Brown   PetscScalar    *tau,*work;
1774194825f6SJed Brown 
1775194825f6SJed Brown   PetscFunctionBegin;
1776194825f6SJed Brown   PetscValidRealPointer(sourcex,3);
1777194825f6SJed Brown   PetscValidRealPointer(targetx,5);
1778194825f6SJed Brown   PetscValidRealPointer(R,6);
1779194825f6SJed 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);
1780194825f6SJed Brown #if defined(PETSC_USE_DEBUG)
1781194825f6SJed Brown   for (i=0; i<nsource; i++) {
178257622a8eSBarry 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]);
1783194825f6SJed Brown   }
1784194825f6SJed Brown   for (i=0; i<ntarget; i++) {
178557622a8eSBarry 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]);
1786194825f6SJed Brown   }
1787194825f6SJed Brown #endif
1788194825f6SJed Brown   xmin = PetscMin(sourcex[0],targetx[0]);
1789194825f6SJed Brown   xmax = PetscMax(sourcex[nsource],targetx[ntarget]);
1790194825f6SJed Brown   center = (xmin + xmax)/2;
1791194825f6SJed Brown   hscale = (xmax - xmin)/2;
1792194825f6SJed Brown   worksize = nsource;
1793dcca6d9dSJed Brown   ierr = PetscMalloc4(degree+1,&bdegrees,nsource+1,&sourcey,nsource*(degree+1),&Bsource,worksize,&work);CHKERRQ(ierr);
1794dcca6d9dSJed Brown   ierr = PetscMalloc4(nsource,&tau,nsource*(degree+1),&Bsinv,ntarget+1,&targety,ntarget*(degree+1),&Btarget);CHKERRQ(ierr);
1795194825f6SJed Brown   for (i=0; i<=nsource; i++) sourcey[i] = (sourcex[i]-center)/hscale;
1796194825f6SJed Brown   for (i=0; i<=degree; i++) bdegrees[i] = i+1;
1797194825f6SJed Brown   ierr = PetscDTLegendreIntegrate(nsource,sourcey,degree+1,bdegrees,PETSC_TRUE,Bsource);CHKERRQ(ierr);
1798194825f6SJed Brown   ierr = PetscDTPseudoInverseQR(nsource,nsource,degree+1,Bsource,Bsinv,tau,nsource,work);CHKERRQ(ierr);
1799194825f6SJed Brown   for (i=0; i<=ntarget; i++) targety[i] = (targetx[i]-center)/hscale;
1800194825f6SJed Brown   ierr = PetscDTLegendreIntegrate(ntarget,targety,degree+1,bdegrees,PETSC_FALSE,Btarget);CHKERRQ(ierr);
1801194825f6SJed Brown   for (i=0; i<ntarget; i++) {
1802194825f6SJed Brown     PetscReal rowsum = 0;
1803194825f6SJed Brown     for (j=0; j<nsource; j++) {
1804194825f6SJed Brown       PetscReal sum = 0;
1805194825f6SJed Brown       for (k=0; k<degree+1; k++) {
1806194825f6SJed Brown         sum += Btarget[i*(degree+1)+k] * Bsinv[k*nsource+j];
1807194825f6SJed Brown       }
1808194825f6SJed Brown       R[i*nsource+j] = sum;
1809194825f6SJed Brown       rowsum += sum;
1810194825f6SJed Brown     }
1811194825f6SJed Brown     for (j=0; j<nsource; j++) R[i*nsource+j] /= rowsum; /* normalize each row */
1812194825f6SJed Brown   }
1813194825f6SJed Brown   ierr = PetscFree4(bdegrees,sourcey,Bsource,work);CHKERRQ(ierr);
1814194825f6SJed Brown   ierr = PetscFree4(tau,Bsinv,targety,Btarget);CHKERRQ(ierr);
1815194825f6SJed Brown   PetscFunctionReturn(0);
1816194825f6SJed Brown }
1817916e780bShannah_mairs 
1818916e780bShannah_mairs /*@C
1819916e780bShannah_mairs    PetscGaussLobattoLegendreIntegrate - Compute the L2 integral of a function on the GLL points
1820916e780bShannah_mairs 
1821916e780bShannah_mairs    Not Collective
1822916e780bShannah_mairs 
1823916e780bShannah_mairs    Input Parameter:
1824916e780bShannah_mairs +  n - the number of GLL nodes
1825916e780bShannah_mairs .  nodes - the GLL nodes
1826916e780bShannah_mairs .  weights - the GLL weights
1827916e780bShannah_mairs .  f - the function values at the nodes
1828916e780bShannah_mairs 
1829916e780bShannah_mairs    Output Parameter:
1830916e780bShannah_mairs .  in - the value of the integral
1831916e780bShannah_mairs 
1832916e780bShannah_mairs    Level: beginner
1833916e780bShannah_mairs 
1834916e780bShannah_mairs .seealso: PetscDTGaussLobattoLegendreQuadrature()
1835916e780bShannah_mairs 
1836916e780bShannah_mairs @*/
1837916e780bShannah_mairs PetscErrorCode PetscGaussLobattoLegendreIntegrate(PetscInt n,PetscReal *nodes,PetscReal *weights,const PetscReal *f,PetscReal *in)
1838916e780bShannah_mairs {
1839916e780bShannah_mairs   PetscInt          i;
1840916e780bShannah_mairs 
1841916e780bShannah_mairs   PetscFunctionBegin;
1842916e780bShannah_mairs   *in = 0.;
1843916e780bShannah_mairs   for (i=0; i<n; i++) {
1844916e780bShannah_mairs     *in += f[i]*f[i]*weights[i];
1845916e780bShannah_mairs   }
1846916e780bShannah_mairs   PetscFunctionReturn(0);
1847916e780bShannah_mairs }
1848916e780bShannah_mairs 
1849916e780bShannah_mairs /*@C
1850916e780bShannah_mairs    PetscGaussLobattoLegendreElementLaplacianCreate - computes the Laplacian for a single 1d GLL element
1851916e780bShannah_mairs 
1852916e780bShannah_mairs    Not Collective
1853916e780bShannah_mairs 
1854916e780bShannah_mairs    Input Parameter:
1855916e780bShannah_mairs +  n - the number of GLL nodes
1856916e780bShannah_mairs .  nodes - the GLL nodes
1857916e780bShannah_mairs .  weights - the GLL weights
1858916e780bShannah_mairs 
1859916e780bShannah_mairs    Output Parameter:
1860916e780bShannah_mairs .  A - the stiffness element
1861916e780bShannah_mairs 
1862916e780bShannah_mairs    Level: beginner
1863916e780bShannah_mairs 
1864916e780bShannah_mairs    Notes:
1865916e780bShannah_mairs     Destroy this with PetscGaussLobattoLegendreElementLaplacianDestroy()
1866916e780bShannah_mairs 
1867916e780bShannah_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)
1868916e780bShannah_mairs 
1869916e780bShannah_mairs .seealso: PetscDTGaussLobattoLegendreQuadrature(), PetscGaussLobattoLegendreElementLaplacianDestroy()
1870916e780bShannah_mairs 
1871916e780bShannah_mairs @*/
1872916e780bShannah_mairs PetscErrorCode PetscGaussLobattoLegendreElementLaplacianCreate(PetscInt n,PetscReal *nodes,PetscReal *weights,PetscReal ***AA)
1873916e780bShannah_mairs {
1874916e780bShannah_mairs   PetscReal        **A;
1875916e780bShannah_mairs   PetscErrorCode  ierr;
1876916e780bShannah_mairs   const PetscReal  *gllnodes = nodes;
1877916e780bShannah_mairs   const PetscInt   p = n-1;
1878916e780bShannah_mairs   PetscReal        z0,z1,z2 = -1,x,Lpj,Lpr;
1879916e780bShannah_mairs   PetscInt         i,j,nn,r;
1880916e780bShannah_mairs 
1881916e780bShannah_mairs   PetscFunctionBegin;
1882916e780bShannah_mairs   ierr = PetscMalloc1(n,&A);CHKERRQ(ierr);
1883916e780bShannah_mairs   ierr = PetscMalloc1(n*n,&A[0]);CHKERRQ(ierr);
1884916e780bShannah_mairs   for (i=1; i<n; i++) A[i] = A[i-1]+n;
1885916e780bShannah_mairs 
1886916e780bShannah_mairs   for (j=1; j<p; j++) {
1887916e780bShannah_mairs     x  = gllnodes[j];
1888916e780bShannah_mairs     z0 = 1.;
1889916e780bShannah_mairs     z1 = x;
1890916e780bShannah_mairs     for (nn=1; nn<p; nn++) {
1891916e780bShannah_mairs       z2 = x*z1*(2.*((PetscReal)nn)+1.)/(((PetscReal)nn)+1.)-z0*(((PetscReal)nn)/(((PetscReal)nn)+1.));
1892916e780bShannah_mairs       z0 = z1;
1893916e780bShannah_mairs       z1 = z2;
1894916e780bShannah_mairs     }
1895916e780bShannah_mairs     Lpj=z2;
1896916e780bShannah_mairs     for (r=1; r<p; r++) {
1897916e780bShannah_mairs       if (r == j) {
1898916e780bShannah_mairs         A[j][j]=2./(3.*(1.-gllnodes[j]*gllnodes[j])*Lpj*Lpj);
1899916e780bShannah_mairs       } else {
1900916e780bShannah_mairs         x  = gllnodes[r];
1901916e780bShannah_mairs         z0 = 1.;
1902916e780bShannah_mairs         z1 = x;
1903916e780bShannah_mairs         for (nn=1; nn<p; nn++) {
1904916e780bShannah_mairs           z2 = x*z1*(2.*((PetscReal)nn)+1.)/(((PetscReal)nn)+1.)-z0*(((PetscReal)nn)/(((PetscReal)nn)+1.));
1905916e780bShannah_mairs           z0 = z1;
1906916e780bShannah_mairs           z1 = z2;
1907916e780bShannah_mairs         }
1908916e780bShannah_mairs         Lpr     = z2;
1909916e780bShannah_mairs         A[r][j] = 4./(((PetscReal)p)*(((PetscReal)p)+1.)*Lpj*Lpr*(gllnodes[j]-gllnodes[r])*(gllnodes[j]-gllnodes[r]));
1910916e780bShannah_mairs       }
1911916e780bShannah_mairs     }
1912916e780bShannah_mairs   }
1913916e780bShannah_mairs   for (j=1; j<p+1; j++) {
1914916e780bShannah_mairs     x  = gllnodes[j];
1915916e780bShannah_mairs     z0 = 1.;
1916916e780bShannah_mairs     z1 = x;
1917916e780bShannah_mairs     for (nn=1; nn<p; nn++) {
1918916e780bShannah_mairs       z2 = x*z1*(2.*((PetscReal)nn)+1.)/(((PetscReal)nn)+1.)-z0*(((PetscReal)nn)/(((PetscReal)nn)+1.));
1919916e780bShannah_mairs       z0 = z1;
1920916e780bShannah_mairs       z1 = z2;
1921916e780bShannah_mairs     }
1922916e780bShannah_mairs     Lpj     = z2;
1923916e780bShannah_mairs     A[j][0] = 4.*PetscPowRealInt(-1.,p)/(((PetscReal)p)*(((PetscReal)p)+1.)*Lpj*(1.+gllnodes[j])*(1.+gllnodes[j]));
1924916e780bShannah_mairs     A[0][j] = A[j][0];
1925916e780bShannah_mairs   }
1926916e780bShannah_mairs   for (j=0; j<p; j++) {
1927916e780bShannah_mairs     x  = gllnodes[j];
1928916e780bShannah_mairs     z0 = 1.;
1929916e780bShannah_mairs     z1 = x;
1930916e780bShannah_mairs     for (nn=1; nn<p; nn++) {
1931916e780bShannah_mairs       z2 = x*z1*(2.*((PetscReal)nn)+1.)/(((PetscReal)nn)+1.)-z0*(((PetscReal)nn)/(((PetscReal)nn)+1.));
1932916e780bShannah_mairs       z0 = z1;
1933916e780bShannah_mairs       z1 = z2;
1934916e780bShannah_mairs     }
1935916e780bShannah_mairs     Lpj=z2;
1936916e780bShannah_mairs 
1937916e780bShannah_mairs     A[p][j] = 4./(((PetscReal)p)*(((PetscReal)p)+1.)*Lpj*(1.-gllnodes[j])*(1.-gllnodes[j]));
1938916e780bShannah_mairs     A[j][p] = A[p][j];
1939916e780bShannah_mairs   }
1940916e780bShannah_mairs   A[0][0]=0.5+(((PetscReal)p)*(((PetscReal)p)+1.)-2.)/6.;
1941916e780bShannah_mairs   A[p][p]=A[0][0];
1942916e780bShannah_mairs   *AA = A;
1943916e780bShannah_mairs   PetscFunctionReturn(0);
1944916e780bShannah_mairs }
1945916e780bShannah_mairs 
1946916e780bShannah_mairs /*@C
1947916e780bShannah_mairs    PetscGaussLobattoLegendreElementLaplacianDestroy - frees the Laplacian for a single 1d GLL element
1948916e780bShannah_mairs 
1949916e780bShannah_mairs    Not Collective
1950916e780bShannah_mairs 
1951916e780bShannah_mairs    Input Parameter:
1952916e780bShannah_mairs +  n - the number of GLL nodes
1953916e780bShannah_mairs .  nodes - the GLL nodes
1954916e780bShannah_mairs .  weights - the GLL weightss
1955916e780bShannah_mairs -  A - the stiffness element
1956916e780bShannah_mairs 
1957916e780bShannah_mairs    Level: beginner
1958916e780bShannah_mairs 
1959916e780bShannah_mairs .seealso: PetscDTGaussLobattoLegendreQuadrature(), PetscGaussLobattoLegendreElementLaplacianCreate()
1960916e780bShannah_mairs 
1961916e780bShannah_mairs @*/
1962916e780bShannah_mairs PetscErrorCode PetscGaussLobattoLegendreElementLaplacianDestroy(PetscInt n,PetscReal *nodes,PetscReal *weights,PetscReal ***AA)
1963916e780bShannah_mairs {
1964916e780bShannah_mairs   PetscErrorCode ierr;
1965916e780bShannah_mairs 
1966916e780bShannah_mairs   PetscFunctionBegin;
1967916e780bShannah_mairs   ierr = PetscFree((*AA)[0]);CHKERRQ(ierr);
1968916e780bShannah_mairs   ierr = PetscFree(*AA);CHKERRQ(ierr);
1969916e780bShannah_mairs   *AA  = NULL;
1970916e780bShannah_mairs   PetscFunctionReturn(0);
1971916e780bShannah_mairs }
1972916e780bShannah_mairs 
1973916e780bShannah_mairs /*@C
1974916e780bShannah_mairs    PetscGaussLobattoLegendreElementGradientCreate - computes the gradient for a single 1d GLL element
1975916e780bShannah_mairs 
1976916e780bShannah_mairs    Not Collective
1977916e780bShannah_mairs 
1978916e780bShannah_mairs    Input Parameter:
1979916e780bShannah_mairs +  n - the number of GLL nodes
1980916e780bShannah_mairs .  nodes - the GLL nodes
1981916e780bShannah_mairs .  weights - the GLL weights
1982916e780bShannah_mairs 
1983916e780bShannah_mairs    Output Parameter:
1984916e780bShannah_mairs .  AA - the stiffness element
1985916e780bShannah_mairs -  AAT - the transpose of AA (pass in NULL if you do not need this array)
1986916e780bShannah_mairs 
1987916e780bShannah_mairs    Level: beginner
1988916e780bShannah_mairs 
1989916e780bShannah_mairs    Notes:
1990916e780bShannah_mairs     Destroy this with PetscGaussLobattoLegendreElementGradientDestroy()
1991916e780bShannah_mairs 
1992916e780bShannah_mairs    You can access entries in these arrays with AA[i][j] but in memory it is stored in contiguous memory, row oriented
1993916e780bShannah_mairs 
1994916e780bShannah_mairs .seealso: PetscDTGaussLobattoLegendreQuadrature(), PetscGaussLobattoLegendreElementLaplacianDestroy()
1995916e780bShannah_mairs 
1996916e780bShannah_mairs @*/
1997916e780bShannah_mairs PetscErrorCode PetscGaussLobattoLegendreElementGradientCreate(PetscInt n,PetscReal *nodes,PetscReal *weights,PetscReal ***AA,PetscReal ***AAT)
1998916e780bShannah_mairs {
1999916e780bShannah_mairs   PetscReal        **A, **AT = NULL;
2000916e780bShannah_mairs   PetscErrorCode  ierr;
2001916e780bShannah_mairs   const PetscReal  *gllnodes = nodes;
2002916e780bShannah_mairs   const PetscInt   p = n-1;
2003e6a796c3SToby Isaac   PetscReal        Li, Lj,d0;
2004916e780bShannah_mairs   PetscInt         i,j;
2005916e780bShannah_mairs 
2006916e780bShannah_mairs   PetscFunctionBegin;
2007916e780bShannah_mairs   ierr = PetscMalloc1(n,&A);CHKERRQ(ierr);
2008916e780bShannah_mairs   ierr = PetscMalloc1(n*n,&A[0]);CHKERRQ(ierr);
2009916e780bShannah_mairs   for (i=1; i<n; i++) A[i] = A[i-1]+n;
2010916e780bShannah_mairs 
2011916e780bShannah_mairs   if (AAT) {
2012916e780bShannah_mairs     ierr = PetscMalloc1(n,&AT);CHKERRQ(ierr);
2013916e780bShannah_mairs     ierr = PetscMalloc1(n*n,&AT[0]);CHKERRQ(ierr);
2014916e780bShannah_mairs     for (i=1; i<n; i++) AT[i] = AT[i-1]+n;
2015916e780bShannah_mairs   }
2016916e780bShannah_mairs 
2017916e780bShannah_mairs   if (n==1) {A[0][0] = 0.;}
2018916e780bShannah_mairs   d0 = (PetscReal)p*((PetscReal)p+1.)/4.;
2019916e780bShannah_mairs   for  (i=0; i<n; i++) {
2020916e780bShannah_mairs     for  (j=0; j<n; j++) {
2021916e780bShannah_mairs       A[i][j] = 0.;
2022e6a796c3SToby Isaac       ierr = PetscDTComputeJacobi(0., 0., p, gllnodes[i], &Li);CHKERRQ(ierr);
2023e6a796c3SToby Isaac       ierr = PetscDTComputeJacobi(0., 0., p, gllnodes[j], &Lj);CHKERRQ(ierr);
2024916e780bShannah_mairs       if (i!=j)             A[i][j] = Li/(Lj*(gllnodes[i]-gllnodes[j]));
2025916e780bShannah_mairs       if ((j==i) && (i==0)) A[i][j] = -d0;
2026916e780bShannah_mairs       if (j==i && i==p)     A[i][j] = d0;
2027916e780bShannah_mairs       if (AT) AT[j][i] = A[i][j];
2028916e780bShannah_mairs     }
2029916e780bShannah_mairs   }
2030916e780bShannah_mairs   if (AAT) *AAT = AT;
2031916e780bShannah_mairs   *AA  = A;
2032916e780bShannah_mairs   PetscFunctionReturn(0);
2033916e780bShannah_mairs }
2034916e780bShannah_mairs 
2035916e780bShannah_mairs /*@C
2036916e780bShannah_mairs    PetscGaussLobattoLegendreElementGradientDestroy - frees the gradient for a single 1d GLL element obtained with PetscGaussLobattoLegendreElementGradientCreate()
2037916e780bShannah_mairs 
2038916e780bShannah_mairs    Not Collective
2039916e780bShannah_mairs 
2040916e780bShannah_mairs    Input Parameter:
2041916e780bShannah_mairs +  n - the number of GLL nodes
2042916e780bShannah_mairs .  nodes - the GLL nodes
2043916e780bShannah_mairs .  weights - the GLL weights
2044916e780bShannah_mairs .  AA - the stiffness element
2045916e780bShannah_mairs -  AAT - the transpose of the element
2046916e780bShannah_mairs 
2047916e780bShannah_mairs    Level: beginner
2048916e780bShannah_mairs 
2049916e780bShannah_mairs .seealso: PetscDTGaussLobattoLegendreQuadrature(), PetscGaussLobattoLegendreElementLaplacianCreate(), PetscGaussLobattoLegendreElementAdvectionCreate()
2050916e780bShannah_mairs 
2051916e780bShannah_mairs @*/
2052916e780bShannah_mairs PetscErrorCode PetscGaussLobattoLegendreElementGradientDestroy(PetscInt n,PetscReal *nodes,PetscReal *weights,PetscReal ***AA,PetscReal ***AAT)
2053916e780bShannah_mairs {
2054916e780bShannah_mairs   PetscErrorCode ierr;
2055916e780bShannah_mairs 
2056916e780bShannah_mairs   PetscFunctionBegin;
2057916e780bShannah_mairs   ierr = PetscFree((*AA)[0]);CHKERRQ(ierr);
2058916e780bShannah_mairs   ierr = PetscFree(*AA);CHKERRQ(ierr);
2059916e780bShannah_mairs   *AA  = NULL;
2060916e780bShannah_mairs   if (*AAT) {
2061916e780bShannah_mairs     ierr = PetscFree((*AAT)[0]);CHKERRQ(ierr);
2062916e780bShannah_mairs     ierr = PetscFree(*AAT);CHKERRQ(ierr);
2063916e780bShannah_mairs     *AAT  = NULL;
2064916e780bShannah_mairs   }
2065916e780bShannah_mairs   PetscFunctionReturn(0);
2066916e780bShannah_mairs }
2067916e780bShannah_mairs 
2068916e780bShannah_mairs /*@C
2069916e780bShannah_mairs    PetscGaussLobattoLegendreElementAdvectionCreate - computes the advection operator for a single 1d GLL element
2070916e780bShannah_mairs 
2071916e780bShannah_mairs    Not Collective
2072916e780bShannah_mairs 
2073916e780bShannah_mairs    Input Parameter:
2074916e780bShannah_mairs +  n - the number of GLL nodes
2075916e780bShannah_mairs .  nodes - the GLL nodes
2076916e780bShannah_mairs .  weights - the GLL weightss
2077916e780bShannah_mairs 
2078916e780bShannah_mairs    Output Parameter:
2079916e780bShannah_mairs .  AA - the stiffness element
2080916e780bShannah_mairs 
2081916e780bShannah_mairs    Level: beginner
2082916e780bShannah_mairs 
2083916e780bShannah_mairs    Notes:
2084916e780bShannah_mairs     Destroy this with PetscGaussLobattoLegendreElementAdvectionDestroy()
2085916e780bShannah_mairs 
2086916e780bShannah_mairs    This is the same as the Gradient operator multiplied by the diagonal mass matrix
2087916e780bShannah_mairs 
2088916e780bShannah_mairs    You can access entries in this array with AA[i][j] but in memory it is stored in contiguous memory, row oriented
2089916e780bShannah_mairs 
2090916e780bShannah_mairs .seealso: PetscDTGaussLobattoLegendreQuadrature(), PetscGaussLobattoLegendreElementLaplacianCreate(), PetscGaussLobattoLegendreElementAdvectionDestroy()
2091916e780bShannah_mairs 
2092916e780bShannah_mairs @*/
2093916e780bShannah_mairs PetscErrorCode PetscGaussLobattoLegendreElementAdvectionCreate(PetscInt n,PetscReal *nodes,PetscReal *weights,PetscReal ***AA)
2094916e780bShannah_mairs {
2095916e780bShannah_mairs   PetscReal       **D;
2096916e780bShannah_mairs   PetscErrorCode  ierr;
2097916e780bShannah_mairs   const PetscReal  *gllweights = weights;
2098916e780bShannah_mairs   const PetscInt   glln = n;
2099916e780bShannah_mairs   PetscInt         i,j;
2100916e780bShannah_mairs 
2101916e780bShannah_mairs   PetscFunctionBegin;
2102916e780bShannah_mairs   ierr = PetscGaussLobattoLegendreElementGradientCreate(n,nodes,weights,&D,NULL);CHKERRQ(ierr);
2103916e780bShannah_mairs   for (i=0; i<glln; i++){
2104916e780bShannah_mairs     for (j=0; j<glln; j++) {
2105916e780bShannah_mairs       D[i][j] = gllweights[i]*D[i][j];
2106916e780bShannah_mairs     }
2107916e780bShannah_mairs   }
2108916e780bShannah_mairs   *AA = D;
2109916e780bShannah_mairs   PetscFunctionReturn(0);
2110916e780bShannah_mairs }
2111916e780bShannah_mairs 
2112916e780bShannah_mairs /*@C
2113916e780bShannah_mairs    PetscGaussLobattoLegendreElementAdvectionDestroy - frees the advection stiffness for a single 1d GLL element
2114916e780bShannah_mairs 
2115916e780bShannah_mairs    Not Collective
2116916e780bShannah_mairs 
2117916e780bShannah_mairs    Input Parameter:
2118916e780bShannah_mairs +  n - the number of GLL nodes
2119916e780bShannah_mairs .  nodes - the GLL nodes
2120916e780bShannah_mairs .  weights - the GLL weights
2121916e780bShannah_mairs -  A - advection
2122916e780bShannah_mairs 
2123916e780bShannah_mairs    Level: beginner
2124916e780bShannah_mairs 
2125916e780bShannah_mairs .seealso: PetscDTGaussLobattoLegendreQuadrature(), PetscGaussLobattoLegendreElementAdvectionCreate()
2126916e780bShannah_mairs 
2127916e780bShannah_mairs @*/
2128916e780bShannah_mairs PetscErrorCode PetscGaussLobattoLegendreElementAdvectionDestroy(PetscInt n,PetscReal *nodes,PetscReal *weights,PetscReal ***AA)
2129916e780bShannah_mairs {
2130916e780bShannah_mairs   PetscErrorCode ierr;
2131916e780bShannah_mairs 
2132916e780bShannah_mairs   PetscFunctionBegin;
2133916e780bShannah_mairs   ierr = PetscFree((*AA)[0]);CHKERRQ(ierr);
2134916e780bShannah_mairs   ierr = PetscFree(*AA);CHKERRQ(ierr);
2135916e780bShannah_mairs   *AA  = NULL;
2136916e780bShannah_mairs   PetscFunctionReturn(0);
2137916e780bShannah_mairs }
2138916e780bShannah_mairs 
2139916e780bShannah_mairs PetscErrorCode PetscGaussLobattoLegendreElementMassCreate(PetscInt n,PetscReal *nodes,PetscReal *weights,PetscReal ***AA)
2140916e780bShannah_mairs {
2141916e780bShannah_mairs   PetscReal        **A;
2142916e780bShannah_mairs   PetscErrorCode  ierr;
2143916e780bShannah_mairs   const PetscReal  *gllweights = weights;
2144916e780bShannah_mairs   const PetscInt   glln = n;
2145916e780bShannah_mairs   PetscInt         i,j;
2146916e780bShannah_mairs 
2147916e780bShannah_mairs   PetscFunctionBegin;
2148916e780bShannah_mairs   ierr = PetscMalloc1(glln,&A);CHKERRQ(ierr);
2149916e780bShannah_mairs   ierr = PetscMalloc1(glln*glln,&A[0]);CHKERRQ(ierr);
2150916e780bShannah_mairs   for (i=1; i<glln; i++) A[i] = A[i-1]+glln;
2151916e780bShannah_mairs   if (glln==1) {A[0][0] = 0.;}
2152916e780bShannah_mairs   for  (i=0; i<glln; i++) {
2153916e780bShannah_mairs     for  (j=0; j<glln; j++) {
2154916e780bShannah_mairs       A[i][j] = 0.;
2155916e780bShannah_mairs       if (j==i)     A[i][j] = gllweights[i];
2156916e780bShannah_mairs     }
2157916e780bShannah_mairs   }
2158916e780bShannah_mairs   *AA  = A;
2159916e780bShannah_mairs   PetscFunctionReturn(0);
2160916e780bShannah_mairs }
2161916e780bShannah_mairs 
2162916e780bShannah_mairs PetscErrorCode PetscGaussLobattoLegendreElementMassDestroy(PetscInt n,PetscReal *nodes,PetscReal *weights,PetscReal ***AA)
2163916e780bShannah_mairs {
2164916e780bShannah_mairs   PetscErrorCode ierr;
2165916e780bShannah_mairs 
2166916e780bShannah_mairs   PetscFunctionBegin;
2167916e780bShannah_mairs   ierr = PetscFree((*AA)[0]);CHKERRQ(ierr);
2168916e780bShannah_mairs   ierr = PetscFree(*AA);CHKERRQ(ierr);
2169916e780bShannah_mairs   *AA  = NULL;
2170916e780bShannah_mairs   PetscFunctionReturn(0);
2171916e780bShannah_mairs }
2172