xref: /petsc/src/dm/dt/interface/dt.c (revision f0fc11cebb1bb284829732915f9e84cabc170c2f)
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 
25c4762a1bSJed 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 
3936c877ef6SSatish Balay    Level: intermediate
3946c877ef6SSatish Balay 
395907761f8SToby Isaac .seealso: PetscDTAltVPullback(), PetscDTAltVPullbackMatrix()
396907761f8SToby Isaac @*/
39728222859SToby Isaac PetscErrorCode PetscQuadraturePushForward(PetscQuadrature q, PetscInt imageDim, const PetscReal origin[], const PetscReal originImage[], const PetscReal J[], PetscInt formDegree, PetscQuadrature *Jinvstarq)
398907761f8SToby Isaac {
399907761f8SToby Isaac   PetscInt         dim, Nc, imageNc, formSize, Ncopies, imageFormSize, Npoints, pt, i, j, c;
400907761f8SToby Isaac   const PetscReal *points;
401907761f8SToby Isaac   const PetscReal *weights;
402907761f8SToby Isaac   PetscReal       *imagePoints, *imageWeights;
403907761f8SToby Isaac   PetscReal       *Jinv;
404907761f8SToby Isaac   PetscReal       *Jinvstar;
405907761f8SToby Isaac   PetscErrorCode   ierr;
406907761f8SToby Isaac 
407907761f8SToby Isaac   PetscFunctionBegin;
408907761f8SToby Isaac   PetscValidHeaderSpecific(q, PETSC_OBJECT_CLASSID, 1);
40928222859SToby Isaac   if (imageDim < PetscAbsInt(formDegree)) SETERRQ2(PetscObjectComm((PetscObject)q), PETSC_ERR_ARG_INCOMP, "Cannot represent a %D-form in %D dimensions", PetscAbsInt(formDegree), imageDim);
410907761f8SToby Isaac   ierr = PetscQuadratureGetData(q, &dim, &Nc, &Npoints, &points, &weights);CHKERRQ(ierr);
41128222859SToby Isaac   ierr = PetscDTBinomialInt(dim, PetscAbsInt(formDegree), &formSize);CHKERRQ(ierr);
412907761f8SToby 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);
413907761f8SToby Isaac   Ncopies = Nc / formSize;
41428222859SToby Isaac   ierr = PetscDTBinomialInt(imageDim, PetscAbsInt(formDegree), &imageFormSize);CHKERRQ(ierr);
415907761f8SToby Isaac   imageNc = Ncopies * imageFormSize;
416907761f8SToby Isaac   ierr = PetscMalloc1(Npoints * imageDim, &imagePoints);CHKERRQ(ierr);
417907761f8SToby Isaac   ierr = PetscMalloc1(Npoints * imageNc, &imageWeights);CHKERRQ(ierr);
418907761f8SToby Isaac   ierr = PetscMalloc2(imageDim * dim, &Jinv, formSize * imageFormSize, &Jinvstar);CHKERRQ(ierr);
419907761f8SToby Isaac   ierr = PetscDTJacobianInverse_Internal(dim, imageDim, J, Jinv);CHKERRQ(ierr);
42028222859SToby Isaac   ierr = PetscDTAltVPullbackMatrix(imageDim, dim, Jinv, formDegree, Jinvstar);CHKERRQ(ierr);
421907761f8SToby Isaac   for (pt = 0; pt < Npoints; pt++) {
422907761f8SToby Isaac     const PetscReal *point = &points[pt * dim];
423907761f8SToby Isaac     PetscReal       *imagePoint = &imagePoints[pt * imageDim];
424907761f8SToby Isaac 
425907761f8SToby Isaac     for (i = 0; i < imageDim; i++) {
426907761f8SToby Isaac       PetscReal val = originImage[i];
427907761f8SToby Isaac 
428907761f8SToby Isaac       for (j = 0; j < dim; j++) val += J[i * dim + j] * (point[j] - origin[j]);
429907761f8SToby Isaac       imagePoint[i] = val;
430907761f8SToby Isaac     }
431907761f8SToby Isaac     for (c = 0; c < Ncopies; c++) {
432907761f8SToby Isaac       const PetscReal *form = &weights[pt * Nc + c * formSize];
433907761f8SToby Isaac       PetscReal       *imageForm = &imageWeights[pt * imageNc + c * imageFormSize];
434907761f8SToby Isaac 
435907761f8SToby Isaac       for (i = 0; i < imageFormSize; i++) {
436907761f8SToby Isaac         PetscReal val = 0.;
437907761f8SToby Isaac 
438907761f8SToby Isaac         for (j = 0; j < formSize; j++) val += Jinvstar[i * formSize + j] * form[j];
439907761f8SToby Isaac         imageForm[i] = val;
440907761f8SToby Isaac       }
441907761f8SToby Isaac     }
442907761f8SToby Isaac   }
443907761f8SToby Isaac   ierr = PetscQuadratureCreate(PetscObjectComm((PetscObject)q), Jinvstarq);CHKERRQ(ierr);
444907761f8SToby Isaac   ierr = PetscQuadratureSetData(*Jinvstarq, imageDim, imageNc, Npoints, imagePoints, imageWeights);CHKERRQ(ierr);
445907761f8SToby Isaac   ierr = PetscFree2(Jinv, Jinvstar);CHKERRQ(ierr);
446907761f8SToby Isaac   PetscFunctionReturn(0);
447907761f8SToby Isaac }
448907761f8SToby Isaac 
44940d8ff71SMatthew G. Knepley /*@C
45040d8ff71SMatthew G. Knepley   PetscQuadratureSetData - Sets the data defining the quadrature
45140d8ff71SMatthew G. Knepley 
45240d8ff71SMatthew G. Knepley   Not collective
45340d8ff71SMatthew G. Knepley 
45440d8ff71SMatthew G. Knepley   Input Parameters:
45540d8ff71SMatthew G. Knepley + q  - The PetscQuadrature object
45640d8ff71SMatthew G. Knepley . dim - The spatial dimension
457e2b35d93SBarry Smith . Nc - The number of components
45840d8ff71SMatthew G. Knepley . npoints - The number of quadrature points
45940d8ff71SMatthew G. Knepley . points - The coordinates of each quadrature point
46040d8ff71SMatthew G. Knepley - weights - The weight of each quadrature point
46140d8ff71SMatthew G. Knepley 
462c99e0549SMatthew 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.
463f2fd9e53SMatthew G. Knepley 
46440d8ff71SMatthew G. Knepley   Level: intermediate
46540d8ff71SMatthew G. Knepley 
46640d8ff71SMatthew G. Knepley .seealso: PetscQuadratureCreate(), PetscQuadratureGetData()
46740d8ff71SMatthew G. Knepley @*/
468a6b92713SMatthew G. Knepley PetscErrorCode PetscQuadratureSetData(PetscQuadrature q, PetscInt dim, PetscInt Nc, PetscInt npoints, const PetscReal points[], const PetscReal weights[])
46921454ff5SMatthew G. Knepley {
47021454ff5SMatthew G. Knepley   PetscFunctionBegin;
4712cd22861SMatthew G. Knepley   PetscValidHeaderSpecific(q, PETSCQUADRATURE_CLASSID, 1);
47221454ff5SMatthew G. Knepley   if (dim >= 0)     q->dim       = dim;
473a6b92713SMatthew G. Knepley   if (Nc >= 0)      q->Nc        = Nc;
47421454ff5SMatthew G. Knepley   if (npoints >= 0) q->numPoints = npoints;
47521454ff5SMatthew G. Knepley   if (points) {
47621454ff5SMatthew G. Knepley     PetscValidPointer(points, 4);
47721454ff5SMatthew G. Knepley     q->points = points;
47821454ff5SMatthew G. Knepley   }
47921454ff5SMatthew G. Knepley   if (weights) {
48021454ff5SMatthew G. Knepley     PetscValidPointer(weights, 5);
48121454ff5SMatthew G. Knepley     q->weights = weights;
48221454ff5SMatthew G. Knepley   }
483f9fd7fdbSMatthew G. Knepley   PetscFunctionReturn(0);
484f9fd7fdbSMatthew G. Knepley }
485f9fd7fdbSMatthew G. Knepley 
486d9bac1caSLisandro Dalcin static PetscErrorCode PetscQuadratureView_Ascii(PetscQuadrature quad, PetscViewer v)
487d9bac1caSLisandro Dalcin {
488d9bac1caSLisandro Dalcin   PetscInt          q, d, c;
489d9bac1caSLisandro Dalcin   PetscViewerFormat format;
490d9bac1caSLisandro Dalcin   PetscErrorCode    ierr;
491d9bac1caSLisandro Dalcin 
492d9bac1caSLisandro Dalcin   PetscFunctionBegin;
493c74b4a09SMatthew 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);}
494c74b4a09SMatthew G. Knepley   else              {ierr = PetscViewerASCIIPrintf(v, "Quadrature of order %D on %D points (dim %D)\n", quad->order, quad->numPoints, quad->dim);CHKERRQ(ierr);}
495d9bac1caSLisandro Dalcin   ierr = PetscViewerGetFormat(v, &format);CHKERRQ(ierr);
496d9bac1caSLisandro Dalcin   if (format != PETSC_VIEWER_ASCII_INFO_DETAIL) PetscFunctionReturn(0);
497d9bac1caSLisandro Dalcin   for (q = 0; q < quad->numPoints; ++q) {
498c74b4a09SMatthew G. Knepley     ierr = PetscViewerASCIIPrintf(v, "p%D (", q);CHKERRQ(ierr);
499d9bac1caSLisandro Dalcin     ierr = PetscViewerASCIIUseTabs(v, PETSC_FALSE);CHKERRQ(ierr);
500d9bac1caSLisandro Dalcin     for (d = 0; d < quad->dim; ++d) {
501d9bac1caSLisandro Dalcin       if (d) {ierr = PetscViewerASCIIPrintf(v, ", ");CHKERRQ(ierr);}
502d9bac1caSLisandro Dalcin       ierr = PetscViewerASCIIPrintf(v, "%+g", (double)quad->points[q*quad->dim+d]);CHKERRQ(ierr);
503d9bac1caSLisandro Dalcin     }
504d9bac1caSLisandro Dalcin     ierr = PetscViewerASCIIPrintf(v, ") ");CHKERRQ(ierr);
505c74b4a09SMatthew G. Knepley     if (quad->Nc > 1) {ierr = PetscViewerASCIIPrintf(v, "w%D (", q);CHKERRQ(ierr);}
506d9bac1caSLisandro Dalcin     for (c = 0; c < quad->Nc; ++c) {
507d9bac1caSLisandro Dalcin       if (c) {ierr = PetscViewerASCIIPrintf(v, ", ");CHKERRQ(ierr);}
508c74b4a09SMatthew G. Knepley       ierr = PetscViewerASCIIPrintf(v, "%+g", (double)quad->weights[q*quad->Nc+c]);CHKERRQ(ierr);
509d9bac1caSLisandro Dalcin     }
510d9bac1caSLisandro Dalcin     if (quad->Nc > 1) {ierr = PetscViewerASCIIPrintf(v, ")");CHKERRQ(ierr);}
511d9bac1caSLisandro Dalcin     ierr = PetscViewerASCIIPrintf(v, "\n");CHKERRQ(ierr);
512d9bac1caSLisandro Dalcin     ierr = PetscViewerASCIIUseTabs(v, PETSC_TRUE);CHKERRQ(ierr);
513d9bac1caSLisandro Dalcin   }
514d9bac1caSLisandro Dalcin   PetscFunctionReturn(0);
515d9bac1caSLisandro Dalcin }
516d9bac1caSLisandro Dalcin 
51740d8ff71SMatthew G. Knepley /*@C
51840d8ff71SMatthew G. Knepley   PetscQuadratureView - Views a PetscQuadrature object
51940d8ff71SMatthew G. Knepley 
520d083f849SBarry Smith   Collective on quad
52140d8ff71SMatthew G. Knepley 
52240d8ff71SMatthew G. Knepley   Input Parameters:
523d9bac1caSLisandro Dalcin + quad  - The PetscQuadrature object
52440d8ff71SMatthew G. Knepley - viewer - The PetscViewer object
52540d8ff71SMatthew G. Knepley 
52640d8ff71SMatthew G. Knepley   Level: beginner
52740d8ff71SMatthew G. Knepley 
52840d8ff71SMatthew G. Knepley .seealso: PetscQuadratureCreate(), PetscQuadratureGetData()
52940d8ff71SMatthew G. Knepley @*/
530f9fd7fdbSMatthew G. Knepley PetscErrorCode PetscQuadratureView(PetscQuadrature quad, PetscViewer viewer)
531f9fd7fdbSMatthew G. Knepley {
532d9bac1caSLisandro Dalcin   PetscBool      iascii;
533f9fd7fdbSMatthew G. Knepley   PetscErrorCode ierr;
534f9fd7fdbSMatthew G. Knepley 
535f9fd7fdbSMatthew G. Knepley   PetscFunctionBegin;
536d9bac1caSLisandro Dalcin   PetscValidHeader(quad, 1);
537d9bac1caSLisandro Dalcin   if (viewer) PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
538d9bac1caSLisandro Dalcin   if (!viewer) {ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject) quad), &viewer);CHKERRQ(ierr);}
539d9bac1caSLisandro Dalcin   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
540d9bac1caSLisandro Dalcin   ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
541d9bac1caSLisandro Dalcin   if (iascii) {ierr = PetscQuadratureView_Ascii(quad, viewer);CHKERRQ(ierr);}
542d9bac1caSLisandro Dalcin   ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
543bfa639d9SMatthew G. Knepley   PetscFunctionReturn(0);
544bfa639d9SMatthew G. Knepley }
545bfa639d9SMatthew G. Knepley 
54689710940SMatthew G. Knepley /*@C
54789710940SMatthew G. Knepley   PetscQuadratureExpandComposite - Return a quadrature over the composite element, which has the original quadrature in each subelement
54889710940SMatthew G. Knepley 
54989710940SMatthew G. Knepley   Not collective
55089710940SMatthew G. Knepley 
55189710940SMatthew G. Knepley   Input Parameter:
55289710940SMatthew G. Knepley + q - The original PetscQuadrature
55389710940SMatthew G. Knepley . numSubelements - The number of subelements the original element is divided into
55489710940SMatthew G. Knepley . v0 - An array of the initial points for each subelement
55589710940SMatthew G. Knepley - jac - An array of the Jacobian mappings from the reference to each subelement
55689710940SMatthew G. Knepley 
55789710940SMatthew G. Knepley   Output Parameters:
55889710940SMatthew G. Knepley . dim - The dimension
55989710940SMatthew G. Knepley 
56089710940SMatthew G. Knepley   Note: Together v0 and jac define an affine mapping from the original reference element to each subelement
56189710940SMatthew G. Knepley 
562f5f57ec0SBarry Smith  Not available from Fortran
563f5f57ec0SBarry Smith 
56489710940SMatthew G. Knepley   Level: intermediate
56589710940SMatthew G. Knepley 
56689710940SMatthew G. Knepley .seealso: PetscFECreate(), PetscSpaceGetDimension(), PetscDualSpaceGetDimension()
56789710940SMatthew G. Knepley @*/
56889710940SMatthew G. Knepley PetscErrorCode PetscQuadratureExpandComposite(PetscQuadrature q, PetscInt numSubelements, const PetscReal v0[], const PetscReal jac[], PetscQuadrature *qref)
56989710940SMatthew G. Knepley {
57089710940SMatthew G. Knepley   const PetscReal *points,    *weights;
57189710940SMatthew G. Knepley   PetscReal       *pointsRef, *weightsRef;
572a6b92713SMatthew G. Knepley   PetscInt         dim, Nc, order, npoints, npointsRef, c, p, cp, d, e;
57389710940SMatthew G. Knepley   PetscErrorCode   ierr;
57489710940SMatthew G. Knepley 
57589710940SMatthew G. Knepley   PetscFunctionBegin;
5762cd22861SMatthew G. Knepley   PetscValidHeaderSpecific(q, PETSCQUADRATURE_CLASSID, 1);
57789710940SMatthew G. Knepley   PetscValidPointer(v0, 3);
57889710940SMatthew G. Knepley   PetscValidPointer(jac, 4);
57989710940SMatthew G. Knepley   PetscValidPointer(qref, 5);
58089710940SMatthew G. Knepley   ierr = PetscQuadratureCreate(PETSC_COMM_SELF, qref);CHKERRQ(ierr);
58189710940SMatthew G. Knepley   ierr = PetscQuadratureGetOrder(q, &order);CHKERRQ(ierr);
582a6b92713SMatthew G. Knepley   ierr = PetscQuadratureGetData(q, &dim, &Nc, &npoints, &points, &weights);CHKERRQ(ierr);
58389710940SMatthew G. Knepley   npointsRef = npoints*numSubelements;
58489710940SMatthew G. Knepley   ierr = PetscMalloc1(npointsRef*dim,&pointsRef);CHKERRQ(ierr);
585a6b92713SMatthew G. Knepley   ierr = PetscMalloc1(npointsRef*Nc, &weightsRef);CHKERRQ(ierr);
58689710940SMatthew G. Knepley   for (c = 0; c < numSubelements; ++c) {
58789710940SMatthew G. Knepley     for (p = 0; p < npoints; ++p) {
58889710940SMatthew G. Knepley       for (d = 0; d < dim; ++d) {
58989710940SMatthew G. Knepley         pointsRef[(c*npoints + p)*dim+d] = v0[c*dim+d];
59089710940SMatthew G. Knepley         for (e = 0; e < dim; ++e) {
59189710940SMatthew G. Knepley           pointsRef[(c*npoints + p)*dim+d] += jac[(c*dim + d)*dim+e]*(points[p*dim+e] + 1.0);
59289710940SMatthew G. Knepley         }
59389710940SMatthew G. Knepley       }
59489710940SMatthew G. Knepley       /* Could also use detJ here */
595a6b92713SMatthew G. Knepley       for (cp = 0; cp < Nc; ++cp) weightsRef[(c*npoints+p)*Nc+cp] = weights[p*Nc+cp]/numSubelements;
59689710940SMatthew G. Knepley     }
59789710940SMatthew G. Knepley   }
59889710940SMatthew G. Knepley   ierr = PetscQuadratureSetOrder(*qref, order);CHKERRQ(ierr);
599a6b92713SMatthew G. Knepley   ierr = PetscQuadratureSetData(*qref, dim, Nc, npointsRef, pointsRef, weightsRef);CHKERRQ(ierr);
60089710940SMatthew G. Knepley   PetscFunctionReturn(0);
60189710940SMatthew G. Knepley }
60289710940SMatthew G. Knepley 
60394e21283SToby Isaac /* Compute the coefficients for the Jacobi polynomial recurrence,
60494e21283SToby Isaac  *
60594e21283SToby Isaac  * J^{a,b}_n(x) = (cnm1 + cnm1x * x) * J^{a,b}_{n-1}(x) - cnm2 * J^{a,b}_{n-2}(x).
60694e21283SToby Isaac  */
60794e21283SToby Isaac #define PetscDTJacobiRecurrence_Internal(n,a,b,cnm1,cnm1x,cnm2) \
60894e21283SToby Isaac do {                                                            \
60994e21283SToby Isaac   PetscReal _a = (a);                                           \
61094e21283SToby Isaac   PetscReal _b = (b);                                           \
61194e21283SToby Isaac   PetscReal _n = (n);                                           \
61294e21283SToby Isaac   if (n == 1) {                                                 \
61394e21283SToby Isaac     (cnm1) = (_a-_b) * 0.5;                                     \
61494e21283SToby Isaac     (cnm1x) = (_a+_b+2.)*0.5;                                   \
61594e21283SToby Isaac     (cnm2) = 0.;                                                \
61694e21283SToby Isaac   } else {                                                      \
61794e21283SToby Isaac     PetscReal _2n = _n+_n;                                      \
61894e21283SToby Isaac     PetscReal _d = (_2n*(_n+_a+_b)*(_2n+_a+_b-2));              \
61994e21283SToby Isaac     PetscReal _n1 = (_2n+_a+_b-1.)*(_a*_a-_b*_b);               \
62094e21283SToby Isaac     PetscReal _n1x = (_2n+_a+_b-1.)*(_2n+_a+_b)*(_2n+_a+_b-2);  \
62194e21283SToby Isaac     PetscReal _n2 = 2.*((_n+_a-1.)*(_n+_b-1.)*(_2n+_a+_b));     \
62294e21283SToby Isaac     (cnm1) = _n1 / _d;                                          \
62394e21283SToby Isaac     (cnm1x) = _n1x / _d;                                        \
62494e21283SToby Isaac     (cnm2) = _n2 / _d;                                          \
62594e21283SToby Isaac   }                                                             \
62694e21283SToby Isaac } while (0)
62794e21283SToby Isaac 
62894e21283SToby Isaac static PetscErrorCode PetscDTJacobiEval_Internal(PetscInt npoints, PetscReal a, PetscReal b, PetscInt k, const PetscReal *points, PetscInt ndegree, const PetscInt *degrees, PetscReal *p)
62994e21283SToby Isaac {
63094e21283SToby Isaac   PetscReal ak, bk;
63194e21283SToby Isaac   PetscReal abk1;
63294e21283SToby Isaac   PetscInt i,l,maxdegree;
63394e21283SToby Isaac 
63494e21283SToby Isaac   PetscFunctionBegin;
63594e21283SToby Isaac   maxdegree = degrees[ndegree-1] - k;
63694e21283SToby Isaac   ak = a + k;
63794e21283SToby Isaac   bk = b + k;
63894e21283SToby Isaac   abk1 = a + b + k + 1.;
63994e21283SToby Isaac   if (maxdegree < 0) {
64094e21283SToby Isaac     for (i = 0; i < npoints; i++) for (l = 0; l < ndegree; l++) p[i*ndegree+l] = 0.;
64194e21283SToby Isaac     PetscFunctionReturn(0);
64294e21283SToby Isaac   }
64394e21283SToby Isaac   for (i=0; i<npoints; i++) {
64494e21283SToby Isaac     PetscReal pm1,pm2,x;
64594e21283SToby Isaac     PetscReal cnm1, cnm1x, cnm2;
64694e21283SToby Isaac     PetscInt  j,m;
64794e21283SToby Isaac 
64894e21283SToby Isaac     x    = points[i];
64994e21283SToby Isaac     pm2  = 1.;
65094e21283SToby Isaac     PetscDTJacobiRecurrence_Internal(1,ak,bk,cnm1,cnm1x,cnm2);
65194e21283SToby Isaac     pm1 = (cnm1 + cnm1x*x);
65294e21283SToby Isaac     l    = 0;
65394e21283SToby Isaac     while (l < ndegree && degrees[l] - k < 0) {
65494e21283SToby Isaac       p[l++] = 0.;
65594e21283SToby Isaac     }
65694e21283SToby Isaac     while (l < ndegree && degrees[l] - k == 0) {
65794e21283SToby Isaac       p[l] = pm2;
65894e21283SToby Isaac       for (m = 0; m < k; m++) p[l] *= (abk1 + m) * 0.5;
65994e21283SToby Isaac       l++;
66094e21283SToby Isaac     }
66194e21283SToby Isaac     while (l < ndegree && degrees[l] - k == 1) {
66294e21283SToby Isaac       p[l] = pm1;
66394e21283SToby Isaac       for (m = 0; m < k; m++) p[l] *= (abk1 + 1 + m) * 0.5;
66494e21283SToby Isaac       l++;
66594e21283SToby Isaac     }
66694e21283SToby Isaac     for (j=2; j<=maxdegree; j++) {
66794e21283SToby Isaac       PetscReal pp;
66894e21283SToby Isaac 
66994e21283SToby Isaac       PetscDTJacobiRecurrence_Internal(j,ak,bk,cnm1,cnm1x,cnm2);
67094e21283SToby Isaac       pp   = (cnm1 + cnm1x*x)*pm1 - cnm2*pm2;
67194e21283SToby Isaac       pm2  = pm1;
67294e21283SToby Isaac       pm1  = pp;
67394e21283SToby Isaac       while (l < ndegree && degrees[l] - k == j) {
67494e21283SToby Isaac         p[l] = pp;
67594e21283SToby Isaac         for (m = 0; m < k; m++) p[l] *= (abk1 + j + m) * 0.5;
67694e21283SToby Isaac         l++;
67794e21283SToby Isaac       }
67894e21283SToby Isaac     }
67994e21283SToby Isaac     p += ndegree;
68094e21283SToby Isaac   }
68194e21283SToby Isaac   PetscFunctionReturn(0);
68294e21283SToby Isaac }
68394e21283SToby Isaac 
68437045ce4SJed Brown /*@
68594e21283SToby Isaac    PetscDTJacobiEval - evaluate Jacobi polynomials for the weight function $(1.+x)^{\alpha} (1.-x)^{\beta}$
68694e21283SToby Isaac                        at points
68794e21283SToby Isaac 
68894e21283SToby Isaac    Not Collective
68994e21283SToby Isaac 
69094e21283SToby Isaac    Input Arguments:
69194e21283SToby Isaac +  npoints - number of spatial points to evaluate at
69294e21283SToby Isaac .  alpha - the left exponent > -1
69394e21283SToby Isaac .  beta - the right exponent > -1
69494e21283SToby Isaac .  points - array of locations to evaluate at
69594e21283SToby Isaac .  ndegree - number of basis degrees to evaluate
69694e21283SToby Isaac -  degrees - sorted array of degrees to evaluate
69794e21283SToby Isaac 
69894e21283SToby Isaac    Output Arguments:
69994e21283SToby Isaac +  B - row-oriented basis evaluation matrix B[point*ndegree + degree] (dimension npoints*ndegrees, allocated by caller) (or NULL)
70094e21283SToby Isaac .  D - row-oriented derivative evaluation matrix (or NULL)
70194e21283SToby Isaac -  D2 - row-oriented second derivative evaluation matrix (or NULL)
70294e21283SToby Isaac 
70394e21283SToby Isaac    Level: intermediate
70494e21283SToby Isaac 
70594e21283SToby Isaac .seealso: PetscDTGaussQuadrature()
70694e21283SToby Isaac @*/
70794e21283SToby Isaac PetscErrorCode PetscDTJacobiEval(PetscInt npoints,PetscReal alpha, PetscReal beta, const PetscReal *points,PetscInt ndegree,const PetscInt *degrees,PetscReal *B,PetscReal *D,PetscReal *D2)
70894e21283SToby Isaac {
70994e21283SToby Isaac   PetscErrorCode ierr;
71094e21283SToby Isaac 
71194e21283SToby Isaac   PetscFunctionBegin;
71294e21283SToby Isaac   if (alpha <= -1.) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"alpha must be > -1.");
71394e21283SToby Isaac   if (beta <= -1.) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"beta must be > -1.");
71494e21283SToby Isaac   if (!npoints || !ndegree) PetscFunctionReturn(0);
71594e21283SToby Isaac   if (B)  {ierr = PetscDTJacobiEval_Internal(npoints, alpha, beta, 0, points, ndegree, degrees, B);CHKERRQ(ierr);}
71694e21283SToby Isaac   if (D)  {ierr = PetscDTJacobiEval_Internal(npoints, alpha, beta, 1, points, ndegree, degrees, D);CHKERRQ(ierr);}
71794e21283SToby Isaac   if (D2) {ierr = PetscDTJacobiEval_Internal(npoints, alpha, beta, 2, points, ndegree, degrees, D2);CHKERRQ(ierr);}
71894e21283SToby Isaac   PetscFunctionReturn(0);
71994e21283SToby Isaac }
72094e21283SToby Isaac 
72194e21283SToby Isaac /*@
72294e21283SToby Isaac    PetscDTLegendreEval - evaluate Legendre polynomials at points
72337045ce4SJed Brown 
72437045ce4SJed Brown    Not Collective
72537045ce4SJed Brown 
72637045ce4SJed Brown    Input Arguments:
72737045ce4SJed Brown +  npoints - number of spatial points to evaluate at
72837045ce4SJed Brown .  points - array of locations to evaluate at
72937045ce4SJed Brown .  ndegree - number of basis degrees to evaluate
73037045ce4SJed Brown -  degrees - sorted array of degrees to evaluate
73137045ce4SJed Brown 
73237045ce4SJed Brown    Output Arguments:
7330298fd71SBarry Smith +  B - row-oriented basis evaluation matrix B[point*ndegree + degree] (dimension npoints*ndegrees, allocated by caller) (or NULL)
7340298fd71SBarry Smith .  D - row-oriented derivative evaluation matrix (or NULL)
7350298fd71SBarry Smith -  D2 - row-oriented second derivative evaluation matrix (or NULL)
73637045ce4SJed Brown 
73737045ce4SJed Brown    Level: intermediate
73837045ce4SJed Brown 
73937045ce4SJed Brown .seealso: PetscDTGaussQuadrature()
74037045ce4SJed Brown @*/
74137045ce4SJed Brown PetscErrorCode PetscDTLegendreEval(PetscInt npoints,const PetscReal *points,PetscInt ndegree,const PetscInt *degrees,PetscReal *B,PetscReal *D,PetscReal *D2)
74237045ce4SJed Brown {
74394e21283SToby Isaac   PetscErrorCode ierr;
74437045ce4SJed Brown 
74537045ce4SJed Brown   PetscFunctionBegin;
74694e21283SToby Isaac   ierr = PetscDTJacobiEval(npoints, 0., 0., points, ndegree, degrees, B, D, D2);CHKERRQ(ierr);
74737045ce4SJed Brown   PetscFunctionReturn(0);
74837045ce4SJed Brown }
74937045ce4SJed Brown 
750e6a796c3SToby Isaac /* solve the symmetric tridiagonal eigenvalue system, writing the eigenvalues into eigs and the eigenvectors into V
751e6a796c3SToby Isaac  * with lds n; diag and subdiag are overwritten */
752e6a796c3SToby Isaac static PetscErrorCode PetscDTSymmetricTridiagonalEigensolve(PetscInt n, PetscReal diag[], PetscReal subdiag[],
753e6a796c3SToby Isaac                                                             PetscReal eigs[], PetscScalar V[])
754e6a796c3SToby Isaac {
755e6a796c3SToby Isaac   char jobz = 'V'; /* eigenvalues and eigenvectors */
756e6a796c3SToby Isaac   char range = 'A'; /* all eigenvalues will be found */
757e6a796c3SToby Isaac   PetscReal VL = 0.; /* ignored because range is 'A' */
758e6a796c3SToby Isaac   PetscReal VU = 0.; /* ignored because range is 'A' */
759e6a796c3SToby Isaac   PetscBLASInt IL = 0; /* ignored because range is 'A' */
760e6a796c3SToby Isaac   PetscBLASInt IU = 0; /* ignored because range is 'A' */
761e6a796c3SToby Isaac   PetscReal abstol = 0.; /* unused */
762e6a796c3SToby Isaac   PetscBLASInt bn, bm, ldz; /* bm will equal bn on exit */
763e6a796c3SToby Isaac   PetscBLASInt *isuppz;
764e6a796c3SToby Isaac   PetscBLASInt lwork, liwork;
765e6a796c3SToby Isaac   PetscReal workquery;
766e6a796c3SToby Isaac   PetscBLASInt  iworkquery;
767e6a796c3SToby Isaac   PetscBLASInt *iwork;
768e6a796c3SToby Isaac   PetscBLASInt info;
769e6a796c3SToby Isaac   PetscReal *work = NULL;
770e6a796c3SToby Isaac   PetscErrorCode ierr;
771e6a796c3SToby Isaac 
772e6a796c3SToby Isaac   PetscFunctionBegin;
773e6a796c3SToby Isaac #if !defined(PETSCDTGAUSSIANQUADRATURE_EIG)
774e6a796c3SToby Isaac   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "A LAPACK symmetric tridiagonal eigensolver could not be found");
775e6a796c3SToby Isaac #endif
776e6a796c3SToby Isaac   ierr = PetscBLASIntCast(n, &bn);CHKERRQ(ierr);
777e6a796c3SToby Isaac   ierr = PetscBLASIntCast(n, &ldz);CHKERRQ(ierr);
778e6a796c3SToby Isaac #if !defined(PETSC_MISSING_LAPACK_STEGR)
779e6a796c3SToby Isaac   ierr = PetscMalloc1(2 * n, &isuppz);CHKERRQ(ierr);
780e6a796c3SToby Isaac   lwork = -1;
781e6a796c3SToby Isaac   liwork = -1;
782e6a796c3SToby Isaac   PetscStackCallBLAS("LAPACKstegr",LAPACKstegr_(&jobz,&range,&bn,diag,subdiag,&VL,&VU,&IL,&IU,&abstol,&bm,eigs,V,&ldz,isuppz,&workquery,&lwork,&iworkquery,&liwork,&info));
783e6a796c3SToby Isaac   if (info) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"xSTEGR error");
784e6a796c3SToby Isaac   lwork = (PetscBLASInt) workquery;
785e6a796c3SToby Isaac   liwork = (PetscBLASInt) iworkquery;
786e6a796c3SToby Isaac   ierr = PetscMalloc2(lwork, &work, liwork, &iwork);CHKERRQ(ierr);
787e6a796c3SToby Isaac   ierr = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr);
788e6a796c3SToby Isaac   PetscStackCallBLAS("LAPACKstegr",LAPACKstegr_(&jobz,&range,&bn,diag,subdiag,&VL,&VU,&IL,&IU,&abstol,&bm,eigs,V,&ldz,isuppz,work,&lwork,iwork,&liwork,&info));
789e6a796c3SToby Isaac   ierr = PetscFPTrapPop();CHKERRQ(ierr);
790e6a796c3SToby Isaac   if (info) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"xSTEGR error");
791e6a796c3SToby Isaac   ierr = PetscFree2(work, iwork);CHKERRQ(ierr);
792e6a796c3SToby Isaac   ierr = PetscFree(isuppz);CHKERRQ(ierr);
793e6a796c3SToby Isaac #elif !defined(PETSC_MISSING_LAPACK_STEQR)
794e6a796c3SToby Isaac   jobz = 'I'; /* Compute eigenvalues and eigenvectors of the
795e6a796c3SToby Isaac                  tridiagonal matrix.  Z is initialized to the identity
796e6a796c3SToby Isaac                  matrix. */
797e6a796c3SToby Isaac   ierr = PetscMalloc1(PetscMax(1,2*n-2),&work);CHKERRQ(ierr);
798e6a796c3SToby Isaac   PetscStackCallBLAS("LAPACKsteqr",LAPACKsteqr_("I",&bn,diag,subdiag,V,&ldz,work,&info));
799e6a796c3SToby Isaac   ierr = PetscFPTrapPop();CHKERRQ(ierr);
800e6a796c3SToby Isaac   if (info) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"xSTEQR error");
801e6a796c3SToby Isaac   ierr = PetscFree(work);CHKERRQ(ierr);
802e6a796c3SToby Isaac   ierr = PetscArraycpy(eigs,diag,n);CHKERRQ(ierr);
803e6a796c3SToby Isaac #endif
804e6a796c3SToby Isaac   PetscFunctionReturn(0);
805e6a796c3SToby Isaac }
806e6a796c3SToby Isaac 
807e6a796c3SToby Isaac /* Formula for the weights at the endpoints (-1 and 1) of Gauss-Lobatto-Jacobi
808e6a796c3SToby Isaac  * quadrature rules on the interval [-1, 1] */
809e6a796c3SToby Isaac static PetscErrorCode PetscDTGaussLobattoJacobiEndweights_Internal(PetscInt n, PetscReal alpha, PetscReal beta, PetscReal *leftw, PetscReal *rightw)
810e6a796c3SToby Isaac {
811e6a796c3SToby Isaac   PetscReal twoab1;
812e6a796c3SToby Isaac   PetscInt  m = n - 2;
813e6a796c3SToby Isaac   PetscReal a = alpha + 1.;
814e6a796c3SToby Isaac   PetscReal b = beta + 1.;
815e6a796c3SToby Isaac   PetscReal gra, grb;
816e6a796c3SToby Isaac 
817e6a796c3SToby Isaac   PetscFunctionBegin;
818e6a796c3SToby Isaac   twoab1 = PetscPowReal(2., a + b - 1.);
819e6a796c3SToby Isaac #if defined(PETSC_HAVE_LGAMMA)
820e6a796c3SToby Isaac   grb = PetscExpReal(2. * PetscLGamma(b+1.) + PetscLGamma(m+1.) + PetscLGamma(m+a+1.) -
821e6a796c3SToby Isaac                      (PetscLGamma(m+b+1) + PetscLGamma(m+a+b+1.)));
822e6a796c3SToby Isaac   gra = PetscExpReal(2. * PetscLGamma(a+1.) + PetscLGamma(m+1.) + PetscLGamma(m+b+1.) -
823e6a796c3SToby Isaac                      (PetscLGamma(m+a+1) + PetscLGamma(m+a+b+1.)));
824e6a796c3SToby Isaac #else
825e6a796c3SToby Isaac   {
826e6a796c3SToby Isaac     PetscInt alphai = (PetscInt) alpha;
827e6a796c3SToby Isaac     PetscInt betai = (PetscInt) beta;
82894e21283SToby Isaac     PetscErrorCode ierr;
829e6a796c3SToby Isaac 
830e6a796c3SToby Isaac     if ((PetscReal) alphai == alpha && (PetscReal) betai == beta) {
831e6a796c3SToby Isaac       PetscReal binom1, binom2;
832e6a796c3SToby Isaac 
833e6a796c3SToby Isaac       ierr = PetscDTBinomial(m+b, b, &binom1);CHKERRQ(ierr);
834e6a796c3SToby Isaac       ierr = PetscDTBinomial(m+a+b, b, &binom2);CHKERRQ(ierr);
835e6a796c3SToby Isaac       grb = 1./ (binom1 * binom2);
836e6a796c3SToby Isaac       ierr = PetscDTBinomial(m+a, a, &binom1);CHKERRQ(ierr);
837e6a796c3SToby Isaac       ierr = PetscDTBinomial(m+a+b, a, &binom2);CHKERRQ(ierr);
838e6a796c3SToby Isaac       gra = 1./ (binom1 * binom2);
839e6a796c3SToby Isaac     } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"lgamma() - math routine is unavailable.");
840e6a796c3SToby Isaac   }
841e6a796c3SToby Isaac #endif
842e6a796c3SToby Isaac   *leftw = twoab1 * grb / b;
843e6a796c3SToby Isaac   *rightw = twoab1 * gra / a;
844e6a796c3SToby Isaac   PetscFunctionReturn(0);
845e6a796c3SToby Isaac }
846e6a796c3SToby Isaac 
847e6a796c3SToby Isaac /* Evaluates the nth jacobi polynomial with weight parameters a,b at a point x.
848e6a796c3SToby Isaac    Recurrence relations implemented from the pseudocode given in Karniadakis and Sherwin, Appendix B */
849e6a796c3SToby Isaac PETSC_STATIC_INLINE PetscErrorCode PetscDTComputeJacobi(PetscReal a, PetscReal b, PetscInt n, PetscReal x, PetscReal *P)
850e6a796c3SToby Isaac {
85194e21283SToby Isaac   PetscReal pn1, pn2;
85294e21283SToby Isaac   PetscReal cnm1, cnm1x, cnm2;
853e6a796c3SToby Isaac   PetscInt  k;
854e6a796c3SToby Isaac 
855e6a796c3SToby Isaac   PetscFunctionBegin;
856e6a796c3SToby Isaac   if (!n) {*P = 1.0; PetscFunctionReturn(0);}
85794e21283SToby Isaac   PetscDTJacobiRecurrence_Internal(1,a,b,cnm1,cnm1x,cnm2);
85894e21283SToby Isaac   pn2 = 1.;
85994e21283SToby Isaac   pn1 = cnm1 + cnm1x*x;
86094e21283SToby Isaac   if (n == 1) {*P = pn1; PetscFunctionReturn(0);}
861e6a796c3SToby Isaac   *P  = 0.0;
862e6a796c3SToby Isaac   for (k = 2; k < n+1; ++k) {
86394e21283SToby Isaac     PetscDTJacobiRecurrence_Internal(k,a,b,cnm1,cnm1x,cnm2);
864e6a796c3SToby Isaac 
86594e21283SToby Isaac     *P  = (cnm1 + cnm1x*x)*pn1 - cnm2*pn2;
866e6a796c3SToby Isaac     pn2 = pn1;
867e6a796c3SToby Isaac     pn1 = *P;
868e6a796c3SToby Isaac   }
869e6a796c3SToby Isaac   PetscFunctionReturn(0);
870e6a796c3SToby Isaac }
871e6a796c3SToby Isaac 
872e6a796c3SToby Isaac /* Evaluates the first derivative of P_{n}^{a,b} at a point x. */
873e6a796c3SToby Isaac PETSC_STATIC_INLINE PetscErrorCode PetscDTComputeJacobiDerivative(PetscReal a, PetscReal b, PetscInt n, PetscReal x, PetscInt k, PetscReal *P)
874e6a796c3SToby Isaac {
875e6a796c3SToby Isaac   PetscReal      nP;
876e6a796c3SToby Isaac   PetscInt       i;
877e6a796c3SToby Isaac   PetscErrorCode ierr;
878e6a796c3SToby Isaac 
879e6a796c3SToby Isaac   PetscFunctionBegin;
880e6a796c3SToby Isaac   if (k > n) {*P = 0.0; PetscFunctionReturn(0);}
881e6a796c3SToby Isaac   ierr = PetscDTComputeJacobi(a+k, b+k, n-k, x, &nP);CHKERRQ(ierr);
882e6a796c3SToby Isaac   for (i = 0; i < k; i++) nP *= (a + b + n + 1. + i) * 0.5;
883e6a796c3SToby Isaac   *P = nP;
884e6a796c3SToby Isaac   PetscFunctionReturn(0);
885e6a796c3SToby Isaac }
886e6a796c3SToby Isaac 
887e6a796c3SToby Isaac /* Maps from [-1,1]^2 to the (-1,1) reference triangle */
888e6a796c3SToby Isaac PETSC_STATIC_INLINE PetscErrorCode PetscDTMapSquareToTriangle_Internal(PetscReal x, PetscReal y, PetscReal *xi, PetscReal *eta)
889e6a796c3SToby Isaac {
890e6a796c3SToby Isaac   PetscFunctionBegin;
891e6a796c3SToby Isaac   *xi  = 0.5 * (1.0 + x) * (1.0 - y) - 1.0;
892e6a796c3SToby Isaac   *eta = y;
893e6a796c3SToby Isaac   PetscFunctionReturn(0);
894e6a796c3SToby Isaac }
895e6a796c3SToby Isaac 
896e6a796c3SToby Isaac static PetscErrorCode PetscDTGaussJacobiQuadrature_Newton_Internal(PetscInt npoints, PetscReal a, PetscReal b, PetscReal x[], PetscReal w[])
897e6a796c3SToby Isaac {
898e6a796c3SToby Isaac   PetscInt       maxIter = 100;
89994e21283SToby Isaac   PetscReal      eps     = PetscExpReal(0.75 * PetscLogReal(PETSC_MACHINE_EPSILON));
900200b5abcSJed Brown   PetscReal      a1, a6, gf;
901e6a796c3SToby Isaac   PetscInt       k;
902e6a796c3SToby Isaac   PetscErrorCode ierr;
903e6a796c3SToby Isaac 
904e6a796c3SToby Isaac   PetscFunctionBegin;
905e6a796c3SToby Isaac 
906e6a796c3SToby Isaac   a1 = PetscPowReal(2.0, a+b+1);
90794e21283SToby Isaac #if defined(PETSC_HAVE_LGAMMA)
908200b5abcSJed Brown   {
909200b5abcSJed Brown     PetscReal a2, a3, a4, a5;
91094e21283SToby Isaac     a2 = PetscLGamma(a + npoints + 1);
91194e21283SToby Isaac     a3 = PetscLGamma(b + npoints + 1);
91294e21283SToby Isaac     a4 = PetscLGamma(a + b + npoints + 1);
91394e21283SToby Isaac     a5 = PetscLGamma(npoints + 1);
91494e21283SToby Isaac     gf = PetscExpReal(a2 + a3 - (a4 + a5));
915200b5abcSJed Brown   }
916e6a796c3SToby Isaac #else
917e6a796c3SToby Isaac   {
918e6a796c3SToby Isaac     PetscInt ia, ib;
919e6a796c3SToby Isaac 
920e6a796c3SToby Isaac     ia = (PetscInt) a;
921e6a796c3SToby Isaac     ib = (PetscInt) b;
92294e21283SToby Isaac     gf = 1.;
92394e21283SToby Isaac     if (ia == a && ia >= 0) { /* compute ratio of rising factorals wrt a */
92494e21283SToby Isaac       for (k = 0; k < ia; k++) gf *= (npoints + 1. + k) / (npoints + b + 1. + k);
92594e21283SToby Isaac     } else if (b == b && ib >= 0) { /* compute ratio of rising factorials wrt b */
92694e21283SToby Isaac       for (k = 0; k < ib; k++) gf *= (npoints + 1. + k) / (npoints + a + 1. + k);
92794e21283SToby Isaac     } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"lgamma() - math routine is unavailable.");
928e6a796c3SToby Isaac   }
929e6a796c3SToby Isaac #endif
930e6a796c3SToby Isaac 
93194e21283SToby Isaac   a6   = a1 * gf;
932e6a796c3SToby Isaac   /* Computes the m roots of P_{m}^{a,b} on [-1,1] by Newton's method with Chebyshev points as initial guesses.
933e6a796c3SToby Isaac    Algorithm implemented from the pseudocode given by Karniadakis and Sherwin and Python in FIAT */
934e6a796c3SToby Isaac   for (k = 0; k < npoints; ++k) {
93594e21283SToby Isaac     PetscReal r = PetscCosReal(PETSC_PI * (1. - (4.*k + 3. + 2.*b) / (4.*npoints + 2.*(a + b + 1.)))), dP;
936e6a796c3SToby Isaac     PetscInt  j;
937e6a796c3SToby Isaac 
938e6a796c3SToby Isaac     if (k > 0) r = 0.5 * (r + x[k-1]);
939e6a796c3SToby Isaac     for (j = 0; j < maxIter; ++j) {
940e6a796c3SToby Isaac       PetscReal s = 0.0, delta, f, fp;
941e6a796c3SToby Isaac       PetscInt  i;
942e6a796c3SToby Isaac 
943e6a796c3SToby Isaac       for (i = 0; i < k; ++i) s = s + 1.0 / (r - x[i]);
944e6a796c3SToby Isaac       ierr = PetscDTComputeJacobi(a, b, npoints, r, &f);CHKERRQ(ierr);
945e6a796c3SToby Isaac       ierr = PetscDTComputeJacobiDerivative(a, b, npoints, r, 1, &fp);CHKERRQ(ierr);
946e6a796c3SToby Isaac       delta = f / (fp - f * s);
947e6a796c3SToby Isaac       r     = r - delta;
948e6a796c3SToby Isaac       if (PetscAbsReal(delta) < eps) break;
949e6a796c3SToby Isaac     }
950e6a796c3SToby Isaac     x[k] = r;
951e6a796c3SToby Isaac     ierr = PetscDTComputeJacobiDerivative(a, b, npoints, x[k], 1, &dP);CHKERRQ(ierr);
952e6a796c3SToby Isaac     w[k] = a6 / (1.0 - PetscSqr(x[k])) / PetscSqr(dP);
953e6a796c3SToby Isaac   }
954e6a796c3SToby Isaac   PetscFunctionReturn(0);
955e6a796c3SToby Isaac }
956e6a796c3SToby Isaac 
95794e21283SToby Isaac /* Compute the diagonals of the Jacobi matrix used in Golub & Welsch algorithms for Gauss-Jacobi
958e6a796c3SToby Isaac  * quadrature weight calculations on [-1,1] for exponents (1. + x)^a (1.-x)^b */
959e6a796c3SToby Isaac static PetscErrorCode PetscDTJacobiMatrix_Internal(PetscInt nPoints, PetscReal a, PetscReal b, PetscReal *d, PetscReal *s)
960e6a796c3SToby Isaac {
961e6a796c3SToby Isaac   PetscInt       i;
962e6a796c3SToby Isaac 
963e6a796c3SToby Isaac   PetscFunctionBegin;
964e6a796c3SToby Isaac   for (i = 0; i < nPoints; i++) {
96594e21283SToby Isaac     PetscReal A, B, C;
966e6a796c3SToby Isaac 
96794e21283SToby Isaac     PetscDTJacobiRecurrence_Internal(i+1,a,b,A,B,C);
96894e21283SToby Isaac     d[i] = -A / B;
96994e21283SToby Isaac     if (i) s[i-1] *= C / B;
97094e21283SToby Isaac     if (i < nPoints - 1) s[i] = 1. / B;
971e6a796c3SToby Isaac   }
972e6a796c3SToby Isaac   PetscFunctionReturn(0);
973e6a796c3SToby Isaac }
974e6a796c3SToby Isaac 
975e6a796c3SToby Isaac static PetscErrorCode PetscDTGaussJacobiQuadrature_GolubWelsch_Internal(PetscInt npoints, PetscReal a, PetscReal b, PetscReal *x, PetscReal *w)
976e6a796c3SToby Isaac {
977e6a796c3SToby Isaac   PetscReal mu0;
978e6a796c3SToby Isaac   PetscReal ga, gb, gab;
979e6a796c3SToby Isaac   PetscInt i;
980e6a796c3SToby Isaac   PetscErrorCode ierr;
981e6a796c3SToby Isaac 
982e6a796c3SToby Isaac   PetscFunctionBegin;
983e6a796c3SToby Isaac   ierr = PetscCitationsRegister(GolubWelschCitation, &GolubWelschCite);CHKERRQ(ierr);
984e6a796c3SToby Isaac 
985e6a796c3SToby Isaac #if defined(PETSC_HAVE_TGAMMA)
986e6a796c3SToby Isaac   ga  = PetscTGamma(a + 1);
987e6a796c3SToby Isaac   gb  = PetscTGamma(b + 1);
988e6a796c3SToby Isaac   gab = PetscTGamma(a + b + 2);
989e6a796c3SToby Isaac #else
990e6a796c3SToby Isaac   {
991e6a796c3SToby Isaac     PetscInt ia, ib;
992e6a796c3SToby Isaac 
993e6a796c3SToby Isaac     ia = (PetscInt) a;
994e6a796c3SToby Isaac     ib = (PetscInt) b;
995e6a796c3SToby Isaac     if (ia == a && ib == b && ia + 1 > 0 && ib + 1 > 0 && ia + ib + 2 > 0) { /* All gamma(x) terms are (x-1)! terms */
996e6a796c3SToby Isaac       ierr = PetscDTFactorial(ia, &ga);CHKERRQ(ierr);
997e6a796c3SToby Isaac       ierr = PetscDTFactorial(ib, &gb);CHKERRQ(ierr);
998e6a796c3SToby Isaac       ierr = PetscDTFactorial(ia + ib + 1, &gb);CHKERRQ(ierr);
999e6a796c3SToby Isaac     } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"tgamma() - math routine is unavailable.");
1000e6a796c3SToby Isaac   }
1001e6a796c3SToby Isaac #endif
1002e6a796c3SToby Isaac   mu0 = PetscPowReal(2.,a + b + 1.) * ga * gb / gab;
1003e6a796c3SToby Isaac 
1004e6a796c3SToby Isaac #if defined(PETSCDTGAUSSIANQUADRATURE_EIG)
1005e6a796c3SToby Isaac   {
1006e6a796c3SToby Isaac     PetscReal *diag, *subdiag;
1007e6a796c3SToby Isaac     PetscScalar *V;
1008e6a796c3SToby Isaac 
1009e6a796c3SToby Isaac     ierr = PetscMalloc2(npoints, &diag, npoints, &subdiag);CHKERRQ(ierr);
1010e6a796c3SToby Isaac     ierr = PetscMalloc1(npoints*npoints, &V);CHKERRQ(ierr);
1011e6a796c3SToby Isaac     ierr = PetscDTJacobiMatrix_Internal(npoints, a, b, diag, subdiag);CHKERRQ(ierr);
1012e6a796c3SToby Isaac     for (i = 0; i < npoints - 1; i++) subdiag[i] = PetscSqrtReal(subdiag[i]);
1013e6a796c3SToby Isaac     ierr = PetscDTSymmetricTridiagonalEigensolve(npoints, diag, subdiag, x, V);CHKERRQ(ierr);
101494e21283SToby Isaac     for (i = 0; i < npoints; i++) w[i] = PetscSqr(PetscRealPart(V[i * npoints])) * mu0;
1015e6a796c3SToby Isaac     ierr = PetscFree(V);CHKERRQ(ierr);
1016e6a796c3SToby Isaac     ierr = PetscFree2(diag, subdiag);CHKERRQ(ierr);
1017e6a796c3SToby Isaac   }
1018e6a796c3SToby Isaac #else
1019e6a796c3SToby Isaac   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP_SYS, "A LAPACK symmetric tridiagonal eigensolver could not be found");
1020e6a796c3SToby Isaac #endif
102194e21283SToby Isaac   { /* As of March 2, 2020, The Sun Performance Library breaks the LAPACK contract for xstegr and xsteqr: the
102294e21283SToby Isaac        eigenvalues are not guaranteed to be in ascending order.  So we heave a passive aggressive sigh and check that
102394e21283SToby Isaac        the eigenvalues are sorted */
102494e21283SToby Isaac     PetscBool sorted;
102594e21283SToby Isaac 
102694e21283SToby Isaac     ierr = PetscSortedReal(npoints, x, &sorted);CHKERRQ(ierr);
102794e21283SToby Isaac     if (!sorted) {
102894e21283SToby Isaac       PetscInt *order, i;
102994e21283SToby Isaac       PetscReal *tmp;
103094e21283SToby Isaac 
103194e21283SToby Isaac       ierr = PetscMalloc2(npoints, &order, npoints, &tmp);CHKERRQ(ierr);
103294e21283SToby Isaac       for (i = 0; i < npoints; i++) order[i] = i;
103394e21283SToby Isaac       ierr = PetscSortRealWithPermutation(npoints, x, order);CHKERRQ(ierr);
103494e21283SToby Isaac       ierr = PetscArraycpy(tmp, x, npoints);CHKERRQ(ierr);
103594e21283SToby Isaac       for (i = 0; i < npoints; i++) x[i] = tmp[order[i]];
103694e21283SToby Isaac       ierr = PetscArraycpy(tmp, w, npoints);CHKERRQ(ierr);
103794e21283SToby Isaac       for (i = 0; i < npoints; i++) w[i] = tmp[order[i]];
103894e21283SToby Isaac       ierr = PetscFree2(order, tmp);CHKERRQ(ierr);
103994e21283SToby Isaac     }
104094e21283SToby Isaac   }
1041e6a796c3SToby Isaac   PetscFunctionReturn(0);
1042e6a796c3SToby Isaac }
1043e6a796c3SToby Isaac 
1044e6a796c3SToby Isaac static PetscErrorCode PetscDTGaussJacobiQuadrature_Internal(PetscInt npoints,PetscReal alpha, PetscReal beta, PetscReal x[], PetscReal w[], PetscBool newton)
1045e6a796c3SToby Isaac {
1046e6a796c3SToby Isaac   PetscErrorCode ierr;
1047e6a796c3SToby Isaac 
1048e6a796c3SToby Isaac   PetscFunctionBegin;
1049e6a796c3SToby Isaac   if (npoints < 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Number of points must be positive");
1050e6a796c3SToby Isaac   /* If asking for a 1D Lobatto point, just return the non-Lobatto 1D point */
1051e6a796c3SToby Isaac   if (alpha <= -1.) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"alpha must be > -1.");
1052e6a796c3SToby Isaac   if (beta <= -1.) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"beta must be > -1.");
1053e6a796c3SToby Isaac 
1054e6a796c3SToby Isaac   if (newton) {
1055e6a796c3SToby Isaac     ierr = PetscDTGaussJacobiQuadrature_Newton_Internal(npoints, alpha, beta, x, w);CHKERRQ(ierr);
1056e6a796c3SToby Isaac   } else {
1057e6a796c3SToby Isaac     ierr = PetscDTGaussJacobiQuadrature_GolubWelsch_Internal(npoints, alpha, beta, x, w);CHKERRQ(ierr);
1058e6a796c3SToby Isaac   }
1059e6a796c3SToby Isaac   if (alpha == beta) { /* symmetrize */
1060e6a796c3SToby Isaac     PetscInt i;
1061e6a796c3SToby Isaac     for (i = 0; i < (npoints + 1) / 2; i++) {
1062e6a796c3SToby Isaac       PetscInt  j  = npoints - 1 - i;
1063e6a796c3SToby Isaac       PetscReal xi = x[i];
1064e6a796c3SToby Isaac       PetscReal xj = x[j];
1065e6a796c3SToby Isaac       PetscReal wi = w[i];
1066e6a796c3SToby Isaac       PetscReal wj = w[j];
1067e6a796c3SToby Isaac 
1068e6a796c3SToby Isaac       x[i] = (xi - xj) / 2.;
1069e6a796c3SToby Isaac       x[j] = (xj - xi) / 2.;
1070e6a796c3SToby Isaac       w[i] = w[j] = (wi + wj) / 2.;
1071e6a796c3SToby Isaac     }
1072e6a796c3SToby Isaac   }
1073e6a796c3SToby Isaac   PetscFunctionReturn(0);
1074e6a796c3SToby Isaac }
1075e6a796c3SToby Isaac 
107694e21283SToby Isaac /*@
107794e21283SToby Isaac   PetscDTGaussJacobiQuadrature - quadrature for the interval [a, b] with the weight function
107894e21283SToby Isaac   $(x-a)^\alpha (x-b)^\beta$.
107994e21283SToby Isaac 
108094e21283SToby Isaac   Not collective
108194e21283SToby Isaac 
108294e21283SToby Isaac   Input Parameters:
108394e21283SToby Isaac + npoints - the number of points in the quadrature rule
108494e21283SToby Isaac . a - the left endpoint of the interval
108594e21283SToby Isaac . b - the right endpoint of the interval
108694e21283SToby Isaac . alpha - the left exponent
108794e21283SToby Isaac - beta - the right exponent
108894e21283SToby Isaac 
108994e21283SToby Isaac   Output Parameters:
109094e21283SToby Isaac + x - array of length npoints, the locations of the quadrature points
109194e21283SToby Isaac - w - array of length npoints, the weights of the quadrature points
109294e21283SToby Isaac 
109394e21283SToby Isaac   Level: intermediate
109494e21283SToby Isaac 
109594e21283SToby Isaac   Note: this quadrature rule is exact for polynomials up to degree 2*npoints - 1.
109694e21283SToby Isaac @*/
109794e21283SToby Isaac PetscErrorCode PetscDTGaussJacobiQuadrature(PetscInt npoints,PetscReal a, PetscReal b, PetscReal alpha, PetscReal beta, PetscReal x[], PetscReal w[])
1098e6a796c3SToby Isaac {
109994e21283SToby Isaac   PetscInt       i;
1100e6a796c3SToby Isaac   PetscErrorCode ierr;
1101e6a796c3SToby Isaac 
1102e6a796c3SToby Isaac   PetscFunctionBegin;
110394e21283SToby Isaac   ierr = PetscDTGaussJacobiQuadrature_Internal(npoints, alpha, beta, x, w, PetscDTGaussQuadratureNewton_Internal);CHKERRQ(ierr);
110494e21283SToby Isaac   if (a != -1. || b != 1.) { /* shift */
110594e21283SToby Isaac     for (i = 0; i < npoints; i++) {
110694e21283SToby Isaac       x[i] = (x[i] + 1.) * ((b - a) / 2.) + a;
110794e21283SToby Isaac       w[i] *= (b - a) / 2.;
110894e21283SToby Isaac     }
110994e21283SToby Isaac   }
1110e6a796c3SToby Isaac   PetscFunctionReturn(0);
1111e6a796c3SToby Isaac }
1112e6a796c3SToby Isaac 
1113e6a796c3SToby Isaac static PetscErrorCode PetscDTGaussLobattoJacobiQuadrature_Internal(PetscInt npoints,PetscReal alpha, PetscReal beta, PetscReal x[], PetscReal w[], PetscBool newton)
1114e6a796c3SToby Isaac {
1115e6a796c3SToby Isaac   PetscInt       i;
1116e6a796c3SToby Isaac   PetscErrorCode ierr;
1117e6a796c3SToby Isaac 
1118e6a796c3SToby Isaac   PetscFunctionBegin;
1119e6a796c3SToby Isaac   if (npoints < 2) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Number of points must be positive");
1120e6a796c3SToby Isaac   /* If asking for a 1D Lobatto point, just return the non-Lobatto 1D point */
1121e6a796c3SToby Isaac   if (alpha <= -1.) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"alpha must be > -1.");
1122e6a796c3SToby Isaac   if (beta <= -1.) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"beta must be > -1.");
1123e6a796c3SToby Isaac 
1124e6a796c3SToby Isaac   x[0] = -1.;
1125e6a796c3SToby Isaac   x[npoints-1] = 1.;
112694e21283SToby Isaac   if (npoints > 2) {
112794e21283SToby Isaac     ierr = PetscDTGaussJacobiQuadrature_Internal(npoints-2, alpha+1., beta+1., &x[1], &w[1], newton);CHKERRQ(ierr);
112894e21283SToby Isaac   }
1129e6a796c3SToby Isaac   for (i = 1; i < npoints - 1; i++) {
1130e6a796c3SToby Isaac     w[i] /= (1. - x[i]*x[i]);
1131e6a796c3SToby Isaac   }
1132e6a796c3SToby Isaac   ierr = PetscDTGaussLobattoJacobiEndweights_Internal(npoints, alpha, beta, &w[0], &w[npoints-1]);CHKERRQ(ierr);
1133e6a796c3SToby Isaac   PetscFunctionReturn(0);
1134e6a796c3SToby Isaac }
1135e6a796c3SToby Isaac 
113637045ce4SJed Brown /*@
113794e21283SToby Isaac   PetscDTGaussLobattoJacobiQuadrature - quadrature for the interval [a, b] with the weight function
113894e21283SToby Isaac   $(x-a)^\alpha (x-b)^\beta$, with endpoints a and b included as quadrature points.
113994e21283SToby Isaac 
114094e21283SToby Isaac   Not collective
114194e21283SToby Isaac 
114294e21283SToby Isaac   Input Parameters:
114394e21283SToby Isaac + npoints - the number of points in the quadrature rule
114494e21283SToby Isaac . a - the left endpoint of the interval
114594e21283SToby Isaac . b - the right endpoint of the interval
114694e21283SToby Isaac . alpha - the left exponent
114794e21283SToby Isaac - beta - the right exponent
114894e21283SToby Isaac 
114994e21283SToby Isaac   Output Parameters:
115094e21283SToby Isaac + x - array of length npoints, the locations of the quadrature points
115194e21283SToby Isaac - w - array of length npoints, the weights of the quadrature points
115294e21283SToby Isaac 
115394e21283SToby Isaac   Level: intermediate
115494e21283SToby Isaac 
115594e21283SToby Isaac   Note: this quadrature rule is exact for polynomials up to degree 2*npoints - 3.
115694e21283SToby Isaac @*/
115794e21283SToby Isaac PetscErrorCode PetscDTGaussLobattoJacobiQuadrature(PetscInt npoints,PetscReal a, PetscReal b, PetscReal alpha, PetscReal beta, PetscReal x[], PetscReal w[])
115894e21283SToby Isaac {
115994e21283SToby Isaac   PetscInt       i;
116094e21283SToby Isaac   PetscErrorCode ierr;
116194e21283SToby Isaac 
116294e21283SToby Isaac   PetscFunctionBegin;
116394e21283SToby Isaac   ierr = PetscDTGaussLobattoJacobiQuadrature_Internal(npoints, alpha, beta, x, w, PetscDTGaussQuadratureNewton_Internal);CHKERRQ(ierr);
116494e21283SToby Isaac   if (a != -1. || b != 1.) { /* shift */
116594e21283SToby Isaac     for (i = 0; i < npoints; i++) {
116694e21283SToby Isaac       x[i] = (x[i] + 1.) * ((b - a) / 2.) + a;
116794e21283SToby Isaac       w[i] *= (b - a) / 2.;
116894e21283SToby Isaac     }
116994e21283SToby Isaac   }
117094e21283SToby Isaac   PetscFunctionReturn(0);
117194e21283SToby Isaac }
117294e21283SToby Isaac 
117394e21283SToby Isaac /*@
1174e6a796c3SToby Isaac    PetscDTGaussQuadrature - create Gauss-Legendre quadrature
117537045ce4SJed Brown 
117637045ce4SJed Brown    Not Collective
117737045ce4SJed Brown 
117837045ce4SJed Brown    Input Arguments:
117937045ce4SJed Brown +  npoints - number of points
118037045ce4SJed Brown .  a - left end of interval (often-1)
118137045ce4SJed Brown -  b - right end of interval (often +1)
118237045ce4SJed Brown 
118337045ce4SJed Brown    Output Arguments:
118437045ce4SJed Brown +  x - quadrature points
118537045ce4SJed Brown -  w - quadrature weights
118637045ce4SJed Brown 
118737045ce4SJed Brown    Level: intermediate
118837045ce4SJed Brown 
118937045ce4SJed Brown    References:
119096a0c994SBarry Smith .   1. - Golub and Welsch, Calculation of Quadrature Rules, Math. Comp. 23(106), 1969.
119137045ce4SJed Brown 
119237045ce4SJed Brown .seealso: PetscDTLegendreEval()
119337045ce4SJed Brown @*/
119437045ce4SJed Brown PetscErrorCode PetscDTGaussQuadrature(PetscInt npoints,PetscReal a,PetscReal b,PetscReal *x,PetscReal *w)
119537045ce4SJed Brown {
119637045ce4SJed Brown   PetscInt       i;
1197e6a796c3SToby Isaac   PetscErrorCode ierr;
119837045ce4SJed Brown 
119937045ce4SJed Brown   PetscFunctionBegin;
120094e21283SToby Isaac   ierr = PetscDTGaussJacobiQuadrature_Internal(npoints, 0., 0., x, w, PetscDTGaussQuadratureNewton_Internal);CHKERRQ(ierr);
120194e21283SToby Isaac   if (a != -1. || b != 1.) { /* shift */
120237045ce4SJed Brown     for (i = 0; i < npoints; i++) {
1203e6a796c3SToby Isaac       x[i] = (x[i] + 1.) * ((b - a) / 2.) + a;
1204e6a796c3SToby Isaac       w[i] *= (b - a) / 2.;
120537045ce4SJed Brown     }
120637045ce4SJed Brown   }
120737045ce4SJed Brown   PetscFunctionReturn(0);
120837045ce4SJed Brown }
1209194825f6SJed Brown 
12108272889dSSatish Balay /*@C
12118272889dSSatish Balay    PetscDTGaussLobattoLegendreQuadrature - creates a set of the locations and weights of the Gauss-Lobatto-Legendre
12128272889dSSatish Balay                       nodes of a given size on the domain [-1,1]
12138272889dSSatish Balay 
12148272889dSSatish Balay    Not Collective
12158272889dSSatish Balay 
12168272889dSSatish Balay    Input Parameter:
12178272889dSSatish Balay +  n - number of grid nodes
1218f2e8fe4dShannah_mairs -  type - PETSCGAUSSLOBATTOLEGENDRE_VIA_LINEAR_ALGEBRA or PETSCGAUSSLOBATTOLEGENDRE_VIA_NEWTON
12198272889dSSatish Balay 
12208272889dSSatish Balay    Output Arguments:
12218272889dSSatish Balay +  x - quadrature points
12228272889dSSatish Balay -  w - quadrature weights
12238272889dSSatish Balay 
12248272889dSSatish Balay    Notes:
12258272889dSSatish Balay     For n > 30  the Newton approach computes duplicate (incorrect) values for some nodes because the initial guess is apparently not
12268272889dSSatish Balay           close enough to the desired solution
12278272889dSSatish Balay 
12288272889dSSatish Balay    These are useful for implementing spectral methods based on Gauss-Lobatto-Legendre (GLL) nodes
12298272889dSSatish Balay 
1230a8d69d7bSBarry 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
12318272889dSSatish Balay 
12328272889dSSatish Balay    Level: intermediate
12338272889dSSatish Balay 
12348272889dSSatish Balay .seealso: PetscDTGaussQuadrature()
12358272889dSSatish Balay 
12368272889dSSatish Balay @*/
1237916e780bShannah_mairs PetscErrorCode PetscDTGaussLobattoLegendreQuadrature(PetscInt npoints,PetscGaussLobattoLegendreCreateType type,PetscReal *x,PetscReal *w)
12388272889dSSatish Balay {
1239e6a796c3SToby Isaac   PetscBool      newton;
12408272889dSSatish Balay   PetscErrorCode ierr;
12418272889dSSatish Balay 
12428272889dSSatish Balay   PetscFunctionBegin;
12438272889dSSatish Balay   if (npoints < 2) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Must provide at least 2 grid points per element");
124494e21283SToby Isaac   newton = (PetscBool) (type == PETSCGAUSSLOBATTOLEGENDRE_VIA_NEWTON);
1245e6a796c3SToby Isaac   ierr = PetscDTGaussLobattoJacobiQuadrature_Internal(npoints, 0., 0., x, w, newton);CHKERRQ(ierr);
12468272889dSSatish Balay   PetscFunctionReturn(0);
12478272889dSSatish Balay }
12488272889dSSatish Balay 
1249744bafbcSMatthew G. Knepley /*@
1250744bafbcSMatthew G. Knepley   PetscDTGaussTensorQuadrature - creates a tensor-product Gauss quadrature
1251744bafbcSMatthew G. Knepley 
1252744bafbcSMatthew G. Knepley   Not Collective
1253744bafbcSMatthew G. Knepley 
1254744bafbcSMatthew G. Knepley   Input Arguments:
1255744bafbcSMatthew G. Knepley + dim     - The spatial dimension
1256a6b92713SMatthew G. Knepley . Nc      - The number of components
1257744bafbcSMatthew G. Knepley . npoints - number of points in one dimension
1258744bafbcSMatthew G. Knepley . a       - left end of interval (often-1)
1259744bafbcSMatthew G. Knepley - b       - right end of interval (often +1)
1260744bafbcSMatthew G. Knepley 
1261744bafbcSMatthew G. Knepley   Output Argument:
1262744bafbcSMatthew G. Knepley . q - A PetscQuadrature object
1263744bafbcSMatthew G. Knepley 
1264744bafbcSMatthew G. Knepley   Level: intermediate
1265744bafbcSMatthew G. Knepley 
1266744bafbcSMatthew G. Knepley .seealso: PetscDTGaussQuadrature(), PetscDTLegendreEval()
1267744bafbcSMatthew G. Knepley @*/
1268a6b92713SMatthew G. Knepley PetscErrorCode PetscDTGaussTensorQuadrature(PetscInt dim, PetscInt Nc, PetscInt npoints, PetscReal a, PetscReal b, PetscQuadrature *q)
1269744bafbcSMatthew G. Knepley {
1270a6b92713SMatthew G. Knepley   PetscInt       totpoints = dim > 1 ? dim > 2 ? npoints*PetscSqr(npoints) : PetscSqr(npoints) : npoints, i, j, k, c;
1271744bafbcSMatthew G. Knepley   PetscReal     *x, *w, *xw, *ww;
1272744bafbcSMatthew G. Knepley   PetscErrorCode ierr;
1273744bafbcSMatthew G. Knepley 
1274744bafbcSMatthew G. Knepley   PetscFunctionBegin;
1275744bafbcSMatthew G. Knepley   ierr = PetscMalloc1(totpoints*dim,&x);CHKERRQ(ierr);
1276a6b92713SMatthew G. Knepley   ierr = PetscMalloc1(totpoints*Nc,&w);CHKERRQ(ierr);
1277744bafbcSMatthew G. Knepley   /* Set up the Golub-Welsch system */
1278744bafbcSMatthew G. Knepley   switch (dim) {
1279744bafbcSMatthew G. Knepley   case 0:
1280744bafbcSMatthew G. Knepley     ierr = PetscFree(x);CHKERRQ(ierr);
1281744bafbcSMatthew G. Knepley     ierr = PetscFree(w);CHKERRQ(ierr);
1282744bafbcSMatthew G. Knepley     ierr = PetscMalloc1(1, &x);CHKERRQ(ierr);
1283a6b92713SMatthew G. Knepley     ierr = PetscMalloc1(Nc, &w);CHKERRQ(ierr);
1284744bafbcSMatthew G. Knepley     x[0] = 0.0;
1285a6b92713SMatthew G. Knepley     for (c = 0; c < Nc; ++c) w[c] = 1.0;
1286744bafbcSMatthew G. Knepley     break;
1287744bafbcSMatthew G. Knepley   case 1:
1288a6b92713SMatthew G. Knepley     ierr = PetscMalloc1(npoints,&ww);CHKERRQ(ierr);
1289a6b92713SMatthew G. Knepley     ierr = PetscDTGaussQuadrature(npoints, a, b, x, ww);CHKERRQ(ierr);
1290a6b92713SMatthew G. Knepley     for (i = 0; i < npoints; ++i) for (c = 0; c < Nc; ++c) w[i*Nc+c] = ww[i];
1291a6b92713SMatthew G. Knepley     ierr = PetscFree(ww);CHKERRQ(ierr);
1292744bafbcSMatthew G. Knepley     break;
1293744bafbcSMatthew G. Knepley   case 2:
1294744bafbcSMatthew G. Knepley     ierr = PetscMalloc2(npoints,&xw,npoints,&ww);CHKERRQ(ierr);
1295744bafbcSMatthew G. Knepley     ierr = PetscDTGaussQuadrature(npoints, a, b, xw, ww);CHKERRQ(ierr);
1296744bafbcSMatthew G. Knepley     for (i = 0; i < npoints; ++i) {
1297744bafbcSMatthew G. Knepley       for (j = 0; j < npoints; ++j) {
1298744bafbcSMatthew G. Knepley         x[(i*npoints+j)*dim+0] = xw[i];
1299744bafbcSMatthew G. Knepley         x[(i*npoints+j)*dim+1] = xw[j];
1300a6b92713SMatthew G. Knepley         for (c = 0; c < Nc; ++c) w[(i*npoints+j)*Nc+c] = ww[i] * ww[j];
1301744bafbcSMatthew G. Knepley       }
1302744bafbcSMatthew G. Knepley     }
1303744bafbcSMatthew G. Knepley     ierr = PetscFree2(xw,ww);CHKERRQ(ierr);
1304744bafbcSMatthew G. Knepley     break;
1305744bafbcSMatthew G. Knepley   case 3:
1306744bafbcSMatthew G. Knepley     ierr = PetscMalloc2(npoints,&xw,npoints,&ww);CHKERRQ(ierr);
1307744bafbcSMatthew G. Knepley     ierr = PetscDTGaussQuadrature(npoints, a, b, xw, ww);CHKERRQ(ierr);
1308744bafbcSMatthew G. Knepley     for (i = 0; i < npoints; ++i) {
1309744bafbcSMatthew G. Knepley       for (j = 0; j < npoints; ++j) {
1310744bafbcSMatthew G. Knepley         for (k = 0; k < npoints; ++k) {
1311744bafbcSMatthew G. Knepley           x[((i*npoints+j)*npoints+k)*dim+0] = xw[i];
1312744bafbcSMatthew G. Knepley           x[((i*npoints+j)*npoints+k)*dim+1] = xw[j];
1313744bafbcSMatthew G. Knepley           x[((i*npoints+j)*npoints+k)*dim+2] = xw[k];
1314a6b92713SMatthew G. Knepley           for (c = 0; c < Nc; ++c) w[((i*npoints+j)*npoints+k)*Nc+c] = ww[i] * ww[j] * ww[k];
1315744bafbcSMatthew G. Knepley         }
1316744bafbcSMatthew G. Knepley       }
1317744bafbcSMatthew G. Knepley     }
1318744bafbcSMatthew G. Knepley     ierr = PetscFree2(xw,ww);CHKERRQ(ierr);
1319744bafbcSMatthew G. Knepley     break;
1320744bafbcSMatthew G. Knepley   default:
1321744bafbcSMatthew G. Knepley     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct quadrature rule for dimension %d", dim);
1322744bafbcSMatthew G. Knepley   }
1323744bafbcSMatthew G. Knepley   ierr = PetscQuadratureCreate(PETSC_COMM_SELF, q);CHKERRQ(ierr);
13242f5fb066SToby Isaac   ierr = PetscQuadratureSetOrder(*q, 2*npoints-1);CHKERRQ(ierr);
1325a6b92713SMatthew G. Knepley   ierr = PetscQuadratureSetData(*q, dim, Nc, totpoints, x, w);CHKERRQ(ierr);
1326d9bac1caSLisandro Dalcin   ierr = PetscObjectChangeTypeName((PetscObject)*q,"GaussTensor");CHKERRQ(ierr);
1327744bafbcSMatthew G. Knepley   PetscFunctionReturn(0);
1328744bafbcSMatthew G. Knepley }
1329744bafbcSMatthew G. Knepley 
1330494e7359SMatthew G. Knepley /* Maps from [-1,1]^2 to the (-1,1) reference triangle */
1331494e7359SMatthew G. Knepley PETSC_STATIC_INLINE PetscErrorCode PetscDTMapCubeToTetrahedron_Internal(PetscReal x, PetscReal y, PetscReal z, PetscReal *xi, PetscReal *eta, PetscReal *zeta)
1332494e7359SMatthew G. Knepley {
1333494e7359SMatthew G. Knepley   PetscFunctionBegin;
1334494e7359SMatthew G. Knepley   *xi   = 0.25 * (1.0 + x) * (1.0 - y) * (1.0 - z) - 1.0;
1335494e7359SMatthew G. Knepley   *eta  = 0.5  * (1.0 + y) * (1.0 - z) - 1.0;
1336494e7359SMatthew G. Knepley   *zeta = z;
1337494e7359SMatthew G. Knepley   PetscFunctionReturn(0);
1338494e7359SMatthew G. Knepley }
1339494e7359SMatthew G. Knepley 
1340494e7359SMatthew G. Knepley 
1341f5f57ec0SBarry Smith /*@
1342e6a796c3SToby Isaac   PetscDTStroudConicalQuadrature - create Stroud conical quadrature for a simplex
1343494e7359SMatthew G. Knepley 
1344494e7359SMatthew G. Knepley   Not Collective
1345494e7359SMatthew G. Knepley 
1346494e7359SMatthew G. Knepley   Input Arguments:
1347494e7359SMatthew G. Knepley + dim     - The simplex dimension
1348a6b92713SMatthew G. Knepley . Nc      - The number of components
1349dcce0ee2SMatthew G. Knepley . npoints - The number of points in one dimension
1350494e7359SMatthew G. Knepley . a       - left end of interval (often-1)
1351494e7359SMatthew G. Knepley - b       - right end of interval (often +1)
1352494e7359SMatthew G. Knepley 
1353744bafbcSMatthew G. Knepley   Output Argument:
1354552aa4f7SMatthew G. Knepley . q - A PetscQuadrature object
1355494e7359SMatthew G. Knepley 
1356494e7359SMatthew G. Knepley   Level: intermediate
1357494e7359SMatthew G. Knepley 
1358494e7359SMatthew G. Knepley   References:
135996a0c994SBarry Smith .  1. - Karniadakis and Sherwin.  FIAT
1360494e7359SMatthew G. Knepley 
1361e6a796c3SToby Isaac   Note: For dim == 1, this is Gauss-Legendre quadrature
1362e6a796c3SToby Isaac 
1363744bafbcSMatthew G. Knepley .seealso: PetscDTGaussTensorQuadrature(), PetscDTGaussQuadrature()
1364494e7359SMatthew G. Knepley @*/
1365e6a796c3SToby Isaac PetscErrorCode PetscDTStroudConicalQuadrature(PetscInt dim, PetscInt Nc, PetscInt npoints, PetscReal a, PetscReal b, PetscQuadrature *q)
1366494e7359SMatthew G. Knepley {
1367dcce0ee2SMatthew G. Knepley   PetscInt       totpoints = dim > 1 ? dim > 2 ? npoints*PetscSqr(npoints) : PetscSqr(npoints) : npoints;
1368494e7359SMatthew G. Knepley   PetscReal     *px, *wx, *py, *wy, *pz, *wz, *x, *w;
1369e6a796c3SToby Isaac   PetscInt       i, j, k, c; PetscErrorCode ierr;
1370494e7359SMatthew G. Knepley 
1371494e7359SMatthew G. Knepley   PetscFunctionBegin;
1372494e7359SMatthew G. Knepley   if ((a != -1.0) || (b != 1.0)) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must use default internal right now");
1373dcce0ee2SMatthew G. Knepley   ierr = PetscMalloc1(totpoints*dim, &x);CHKERRQ(ierr);
1374dcce0ee2SMatthew G. Knepley   ierr = PetscMalloc1(totpoints*Nc, &w);CHKERRQ(ierr);
1375494e7359SMatthew G. Knepley   switch (dim) {
1376707aa5c5SMatthew G. Knepley   case 0:
1377707aa5c5SMatthew G. Knepley     ierr = PetscFree(x);CHKERRQ(ierr);
1378707aa5c5SMatthew G. Knepley     ierr = PetscFree(w);CHKERRQ(ierr);
1379785e854fSJed Brown     ierr = PetscMalloc1(1, &x);CHKERRQ(ierr);
1380a6b92713SMatthew G. Knepley     ierr = PetscMalloc1(Nc, &w);CHKERRQ(ierr);
1381707aa5c5SMatthew G. Knepley     x[0] = 0.0;
1382a6b92713SMatthew G. Knepley     for (c = 0; c < Nc; ++c) w[c] = 1.0;
1383707aa5c5SMatthew G. Knepley     break;
1384494e7359SMatthew G. Knepley   case 1:
1385dcce0ee2SMatthew G. Knepley     ierr = PetscMalloc1(npoints,&wx);CHKERRQ(ierr);
138694e21283SToby Isaac     ierr = PetscDTGaussJacobiQuadrature(npoints, -1., 1., 0.0, 0.0, x, wx);CHKERRQ(ierr);
1387dcce0ee2SMatthew G. Knepley     for (i = 0; i < npoints; ++i) for (c = 0; c < Nc; ++c) w[i*Nc+c] = wx[i];
1388a6b92713SMatthew G. Knepley     ierr = PetscFree(wx);CHKERRQ(ierr);
1389494e7359SMatthew G. Knepley     break;
1390494e7359SMatthew G. Knepley   case 2:
1391dcce0ee2SMatthew G. Knepley     ierr = PetscMalloc4(npoints,&px,npoints,&wx,npoints,&py,npoints,&wy);CHKERRQ(ierr);
139294e21283SToby Isaac     ierr = PetscDTGaussJacobiQuadrature(npoints, -1., 1., 0.0, 0.0, px, wx);CHKERRQ(ierr);
139394e21283SToby Isaac     ierr = PetscDTGaussJacobiQuadrature(npoints, -1., 1., 1.0, 0.0, py, wy);CHKERRQ(ierr);
1394dcce0ee2SMatthew G. Knepley     for (i = 0; i < npoints; ++i) {
1395dcce0ee2SMatthew G. Knepley       for (j = 0; j < npoints; ++j) {
1396dcce0ee2SMatthew G. Knepley         ierr = PetscDTMapSquareToTriangle_Internal(px[i], py[j], &x[(i*npoints+j)*2+0], &x[(i*npoints+j)*2+1]);CHKERRQ(ierr);
1397dcce0ee2SMatthew G. Knepley         for (c = 0; c < Nc; ++c) w[(i*npoints+j)*Nc+c] = 0.5 * wx[i] * wy[j];
1398494e7359SMatthew G. Knepley       }
1399494e7359SMatthew G. Knepley     }
1400494e7359SMatthew G. Knepley     ierr = PetscFree4(px,wx,py,wy);CHKERRQ(ierr);
1401494e7359SMatthew G. Knepley     break;
1402494e7359SMatthew G. Knepley   case 3:
1403dcce0ee2SMatthew G. Knepley     ierr = PetscMalloc6(npoints,&px,npoints,&wx,npoints,&py,npoints,&wy,npoints,&pz,npoints,&wz);CHKERRQ(ierr);
140494e21283SToby Isaac     ierr = PetscDTGaussJacobiQuadrature(npoints, -1., 1., 0.0, 0.0, px, wx);CHKERRQ(ierr);
140594e21283SToby Isaac     ierr = PetscDTGaussJacobiQuadrature(npoints, -1., 1., 1.0, 0.0, py, wy);CHKERRQ(ierr);
140694e21283SToby Isaac     ierr = PetscDTGaussJacobiQuadrature(npoints, -1., 1., 2.0, 0.0, pz, wz);CHKERRQ(ierr);
1407dcce0ee2SMatthew G. Knepley     for (i = 0; i < npoints; ++i) {
1408dcce0ee2SMatthew G. Knepley       for (j = 0; j < npoints; ++j) {
1409dcce0ee2SMatthew G. Knepley         for (k = 0; k < npoints; ++k) {
1410dcce0ee2SMatthew 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);
1411dcce0ee2SMatthew G. Knepley           for (c = 0; c < Nc; ++c) w[((i*npoints+j)*npoints+k)*Nc+c] = 0.125 * wx[i] * wy[j] * wz[k];
1412494e7359SMatthew G. Knepley         }
1413494e7359SMatthew G. Knepley       }
1414494e7359SMatthew G. Knepley     }
1415494e7359SMatthew G. Knepley     ierr = PetscFree6(px,wx,py,wy,pz,wz);CHKERRQ(ierr);
1416494e7359SMatthew G. Knepley     break;
1417494e7359SMatthew G. Knepley   default:
1418494e7359SMatthew G. Knepley     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct quadrature rule for dimension %d", dim);
1419494e7359SMatthew G. Knepley   }
142021454ff5SMatthew G. Knepley   ierr = PetscQuadratureCreate(PETSC_COMM_SELF, q);CHKERRQ(ierr);
14212f5fb066SToby Isaac   ierr = PetscQuadratureSetOrder(*q, 2*npoints-1);CHKERRQ(ierr);
1422dcce0ee2SMatthew G. Knepley   ierr = PetscQuadratureSetData(*q, dim, Nc, totpoints, x, w);CHKERRQ(ierr);
1423d9bac1caSLisandro Dalcin   ierr = PetscObjectChangeTypeName((PetscObject)*q,"GaussJacobi");CHKERRQ(ierr);
1424494e7359SMatthew G. Knepley   PetscFunctionReturn(0);
1425494e7359SMatthew G. Knepley }
1426494e7359SMatthew G. Knepley 
1427f5f57ec0SBarry Smith /*@
1428b3c0f97bSTom Klotz   PetscDTTanhSinhTensorQuadrature - create tanh-sinh quadrature for a tensor product cell
1429b3c0f97bSTom Klotz 
1430b3c0f97bSTom Klotz   Not Collective
1431b3c0f97bSTom Klotz 
1432b3c0f97bSTom Klotz   Input Arguments:
1433b3c0f97bSTom Klotz + dim   - The cell dimension
1434b3c0f97bSTom Klotz . level - The number of points in one dimension, 2^l
1435b3c0f97bSTom Klotz . a     - left end of interval (often-1)
1436b3c0f97bSTom Klotz - b     - right end of interval (often +1)
1437b3c0f97bSTom Klotz 
1438b3c0f97bSTom Klotz   Output Argument:
1439b3c0f97bSTom Klotz . q - A PetscQuadrature object
1440b3c0f97bSTom Klotz 
1441b3c0f97bSTom Klotz   Level: intermediate
1442b3c0f97bSTom Klotz 
1443b3c0f97bSTom Klotz .seealso: PetscDTGaussTensorQuadrature()
1444b3c0f97bSTom Klotz @*/
1445b3c0f97bSTom Klotz PetscErrorCode PetscDTTanhSinhTensorQuadrature(PetscInt dim, PetscInt level, PetscReal a, PetscReal b, PetscQuadrature *q)
1446b3c0f97bSTom Klotz {
1447b3c0f97bSTom Klotz   const PetscInt  p     = 16;                        /* Digits of precision in the evaluation */
1448b3c0f97bSTom Klotz   const PetscReal alpha = (b-a)/2.;                  /* Half-width of the integration interval */
1449b3c0f97bSTom Klotz   const PetscReal beta  = (b+a)/2.;                  /* Center of the integration interval */
1450b3c0f97bSTom Klotz   const PetscReal h     = PetscPowReal(2.0, -level); /* Step size, length between x_k */
1451d84b4d08SMatthew G. Knepley   PetscReal       xk;                                /* Quadrature point x_k on reference domain [-1, 1] */
1452b3c0f97bSTom Klotz   PetscReal       wk    = 0.5*PETSC_PI;              /* Quadrature weight at x_k */
1453b3c0f97bSTom Klotz   PetscReal      *x, *w;
1454b3c0f97bSTom Klotz   PetscInt        K, k, npoints;
1455b3c0f97bSTom Klotz   PetscErrorCode  ierr;
1456b3c0f97bSTom Klotz 
1457b3c0f97bSTom Klotz   PetscFunctionBegin;
1458b3c0f97bSTom Klotz   if (dim > 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Dimension %d not yet implemented", dim);
1459b3c0f97bSTom Klotz   if (!level) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must give a number of significant digits");
1460b3c0f97bSTom Klotz   /* Find K such that the weights are < 32 digits of precision */
1461b3c0f97bSTom Klotz   for (K = 1; PetscAbsReal(PetscLog10Real(wk)) < 2*p; ++K) {
14629add2064SThomas Klotz     wk = 0.5*h*PETSC_PI*PetscCoshReal(K*h)/PetscSqr(PetscCoshReal(0.5*PETSC_PI*PetscSinhReal(K*h)));
1463b3c0f97bSTom Klotz   }
1464b3c0f97bSTom Klotz   ierr = PetscQuadratureCreate(PETSC_COMM_SELF, q);CHKERRQ(ierr);
1465b3c0f97bSTom Klotz   ierr = PetscQuadratureSetOrder(*q, 2*K+1);CHKERRQ(ierr);
1466b3c0f97bSTom Klotz   npoints = 2*K-1;
1467b3c0f97bSTom Klotz   ierr = PetscMalloc1(npoints*dim, &x);CHKERRQ(ierr);
1468b3c0f97bSTom Klotz   ierr = PetscMalloc1(npoints, &w);CHKERRQ(ierr);
1469b3c0f97bSTom Klotz   /* Center term */
1470b3c0f97bSTom Klotz   x[0] = beta;
1471b3c0f97bSTom Klotz   w[0] = 0.5*alpha*PETSC_PI;
1472b3c0f97bSTom Klotz   for (k = 1; k < K; ++k) {
14739add2064SThomas Klotz     wk = 0.5*alpha*h*PETSC_PI*PetscCoshReal(k*h)/PetscSqr(PetscCoshReal(0.5*PETSC_PI*PetscSinhReal(k*h)));
14741118d4bcSLisandro Dalcin     xk = PetscTanhReal(0.5*PETSC_PI*PetscSinhReal(k*h));
1475b3c0f97bSTom Klotz     x[2*k-1] = -alpha*xk+beta;
1476b3c0f97bSTom Klotz     w[2*k-1] = wk;
1477b3c0f97bSTom Klotz     x[2*k+0] =  alpha*xk+beta;
1478b3c0f97bSTom Klotz     w[2*k+0] = wk;
1479b3c0f97bSTom Klotz   }
1480a6b92713SMatthew G. Knepley   ierr = PetscQuadratureSetData(*q, dim, 1, npoints, x, w);CHKERRQ(ierr);
1481b3c0f97bSTom Klotz   PetscFunctionReturn(0);
1482b3c0f97bSTom Klotz }
1483b3c0f97bSTom Klotz 
1484b3c0f97bSTom Klotz PetscErrorCode PetscDTTanhSinhIntegrate(void (*func)(PetscReal, PetscReal *), PetscReal a, PetscReal b, PetscInt digits, PetscReal *sol)
1485b3c0f97bSTom Klotz {
1486b3c0f97bSTom Klotz   const PetscInt  p     = 16;        /* Digits of precision in the evaluation */
1487b3c0f97bSTom Klotz   const PetscReal alpha = (b-a)/2.;  /* Half-width of the integration interval */
1488b3c0f97bSTom Klotz   const PetscReal beta  = (b+a)/2.;  /* Center of the integration interval */
1489b3c0f97bSTom Klotz   PetscReal       h     = 1.0;       /* Step size, length between x_k */
1490b3c0f97bSTom Klotz   PetscInt        l     = 0;         /* Level of refinement, h = 2^{-l} */
1491b3c0f97bSTom Klotz   PetscReal       osum  = 0.0;       /* Integral on last level */
1492b3c0f97bSTom Klotz   PetscReal       psum  = 0.0;       /* Integral on the level before the last level */
1493b3c0f97bSTom Klotz   PetscReal       sum;               /* Integral on current level */
1494446c295cSMatthew G. Knepley   PetscReal       yk;                /* Quadrature point 1 - x_k on reference domain [-1, 1] */
1495b3c0f97bSTom Klotz   PetscReal       lx, rx;            /* Quadrature points to the left and right of 0 on the real domain [a, b] */
1496b3c0f97bSTom Klotz   PetscReal       wk;                /* Quadrature weight at x_k */
1497b3c0f97bSTom Klotz   PetscReal       lval, rval;        /* Terms in the quadature sum to the left and right of 0 */
1498b3c0f97bSTom Klotz   PetscInt        d;                 /* Digits of precision in the integral */
1499b3c0f97bSTom Klotz 
1500b3c0f97bSTom Klotz   PetscFunctionBegin;
1501b3c0f97bSTom Klotz   if (digits <= 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must give a positive number of significant digits");
1502b3c0f97bSTom Klotz   /* Center term */
1503b3c0f97bSTom Klotz   func(beta, &lval);
1504b3c0f97bSTom Klotz   sum = 0.5*alpha*PETSC_PI*lval;
1505b3c0f97bSTom Klotz   /* */
1506b3c0f97bSTom Klotz   do {
1507b3c0f97bSTom Klotz     PetscReal lterm, rterm, maxTerm = 0.0, d1, d2, d3, d4;
1508b3c0f97bSTom Klotz     PetscInt  k = 1;
1509b3c0f97bSTom Klotz 
1510b3c0f97bSTom Klotz     ++l;
1511b3c0f97bSTom Klotz     /* PetscPrintf(PETSC_COMM_SELF, "LEVEL %D sum: %15.15f\n", l, sum); */
1512b3c0f97bSTom Klotz     /* At each level of refinement, h --> h/2 and sum --> sum/2 */
1513b3c0f97bSTom Klotz     psum = osum;
1514b3c0f97bSTom Klotz     osum = sum;
1515b3c0f97bSTom Klotz     h   *= 0.5;
1516b3c0f97bSTom Klotz     sum *= 0.5;
1517b3c0f97bSTom Klotz     do {
15189add2064SThomas Klotz       wk = 0.5*h*PETSC_PI*PetscCoshReal(k*h)/PetscSqr(PetscCoshReal(0.5*PETSC_PI*PetscSinhReal(k*h)));
1519446c295cSMatthew G. Knepley       yk = 1.0/(PetscExpReal(0.5*PETSC_PI*PetscSinhReal(k*h)) * PetscCoshReal(0.5*PETSC_PI*PetscSinhReal(k*h)));
1520446c295cSMatthew G. Knepley       lx = -alpha*(1.0 - yk)+beta;
1521446c295cSMatthew G. Knepley       rx =  alpha*(1.0 - yk)+beta;
1522b3c0f97bSTom Klotz       func(lx, &lval);
1523b3c0f97bSTom Klotz       func(rx, &rval);
1524b3c0f97bSTom Klotz       lterm   = alpha*wk*lval;
1525b3c0f97bSTom Klotz       maxTerm = PetscMax(PetscAbsReal(lterm), maxTerm);
1526b3c0f97bSTom Klotz       sum    += lterm;
1527b3c0f97bSTom Klotz       rterm   = alpha*wk*rval;
1528b3c0f97bSTom Klotz       maxTerm = PetscMax(PetscAbsReal(rterm), maxTerm);
1529b3c0f97bSTom Klotz       sum    += rterm;
1530b3c0f97bSTom Klotz       ++k;
1531b3c0f97bSTom Klotz       /* Only need to evaluate every other point on refined levels */
1532b3c0f97bSTom Klotz       if (l != 1) ++k;
15339add2064SThomas Klotz     } while (PetscAbsReal(PetscLog10Real(wk)) < p); /* Only need to evaluate sum until weights are < 32 digits of precision */
1534b3c0f97bSTom Klotz 
1535b3c0f97bSTom Klotz     d1 = PetscLog10Real(PetscAbsReal(sum - osum));
1536b3c0f97bSTom Klotz     d2 = PetscLog10Real(PetscAbsReal(sum - psum));
1537b3c0f97bSTom Klotz     d3 = PetscLog10Real(maxTerm) - p;
153809d48545SBarry Smith     if (PetscMax(PetscAbsReal(lterm), PetscAbsReal(rterm)) == 0.0) d4 = 0.0;
153909d48545SBarry Smith     else d4 = PetscLog10Real(PetscMax(PetscAbsReal(lterm), PetscAbsReal(rterm)));
1540b3c0f97bSTom Klotz     d  = PetscAbsInt(PetscMin(0, PetscMax(PetscMax(PetscMax(PetscSqr(d1)/d2, 2*d1), d3), d4)));
15419add2064SThomas Klotz   } while (d < digits && l < 12);
1542b3c0f97bSTom Klotz   *sol = sum;
1543e510cb1fSThomas Klotz 
1544b3c0f97bSTom Klotz   PetscFunctionReturn(0);
1545b3c0f97bSTom Klotz }
1546b3c0f97bSTom Klotz 
1547497880caSRichard Tran Mills #if defined(PETSC_HAVE_MPFR)
154829f144ccSMatthew G. Knepley PetscErrorCode PetscDTTanhSinhIntegrateMPFR(void (*func)(PetscReal, PetscReal *), PetscReal a, PetscReal b, PetscInt digits, PetscReal *sol)
154929f144ccSMatthew G. Knepley {
1550e510cb1fSThomas Klotz   const PetscInt  safetyFactor = 2;  /* Calculate abcissa until 2*p digits */
155129f144ccSMatthew G. Knepley   PetscInt        l            = 0;  /* Level of refinement, h = 2^{-l} */
155229f144ccSMatthew G. Knepley   mpfr_t          alpha;             /* Half-width of the integration interval */
155329f144ccSMatthew G. Knepley   mpfr_t          beta;              /* Center of the integration interval */
155429f144ccSMatthew G. Knepley   mpfr_t          h;                 /* Step size, length between x_k */
155529f144ccSMatthew G. Knepley   mpfr_t          osum;              /* Integral on last level */
155629f144ccSMatthew G. Knepley   mpfr_t          psum;              /* Integral on the level before the last level */
155729f144ccSMatthew G. Knepley   mpfr_t          sum;               /* Integral on current level */
155829f144ccSMatthew G. Knepley   mpfr_t          yk;                /* Quadrature point 1 - x_k on reference domain [-1, 1] */
155929f144ccSMatthew G. Knepley   mpfr_t          lx, rx;            /* Quadrature points to the left and right of 0 on the real domain [a, b] */
156029f144ccSMatthew G. Knepley   mpfr_t          wk;                /* Quadrature weight at x_k */
156129f144ccSMatthew G. Knepley   PetscReal       lval, rval;        /* Terms in the quadature sum to the left and right of 0 */
156229f144ccSMatthew G. Knepley   PetscInt        d;                 /* Digits of precision in the integral */
156329f144ccSMatthew G. Knepley   mpfr_t          pi2, kh, msinh, mcosh, maxTerm, curTerm, tmp;
156429f144ccSMatthew G. Knepley 
156529f144ccSMatthew G. Knepley   PetscFunctionBegin;
156629f144ccSMatthew G. Knepley   if (digits <= 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Must give a positive number of significant digits");
156729f144ccSMatthew G. Knepley   /* Create high precision storage */
1568c9f744b5SMatthew 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);
156929f144ccSMatthew G. Knepley   /* Initialization */
157029f144ccSMatthew G. Knepley   mpfr_set_d(alpha, 0.5*(b-a), MPFR_RNDN);
157129f144ccSMatthew G. Knepley   mpfr_set_d(beta,  0.5*(b+a), MPFR_RNDN);
157229f144ccSMatthew G. Knepley   mpfr_set_d(osum,  0.0,       MPFR_RNDN);
157329f144ccSMatthew G. Knepley   mpfr_set_d(psum,  0.0,       MPFR_RNDN);
157429f144ccSMatthew G. Knepley   mpfr_set_d(h,     1.0,       MPFR_RNDN);
157529f144ccSMatthew G. Knepley   mpfr_const_pi(pi2, MPFR_RNDN);
157629f144ccSMatthew G. Knepley   mpfr_mul_d(pi2, pi2, 0.5, MPFR_RNDN);
157729f144ccSMatthew G. Knepley   /* Center term */
157829f144ccSMatthew G. Knepley   func(0.5*(b+a), &lval);
157929f144ccSMatthew G. Knepley   mpfr_set(sum, pi2, MPFR_RNDN);
158029f144ccSMatthew G. Knepley   mpfr_mul(sum, sum, alpha, MPFR_RNDN);
158129f144ccSMatthew G. Knepley   mpfr_mul_d(sum, sum, lval, MPFR_RNDN);
158229f144ccSMatthew G. Knepley   /* */
158329f144ccSMatthew G. Knepley   do {
158429f144ccSMatthew G. Knepley     PetscReal d1, d2, d3, d4;
158529f144ccSMatthew G. Knepley     PetscInt  k = 1;
158629f144ccSMatthew G. Knepley 
158729f144ccSMatthew G. Knepley     ++l;
158829f144ccSMatthew G. Knepley     mpfr_set_d(maxTerm, 0.0, MPFR_RNDN);
158929f144ccSMatthew G. Knepley     /* PetscPrintf(PETSC_COMM_SELF, "LEVEL %D sum: %15.15f\n", l, sum); */
159029f144ccSMatthew G. Knepley     /* At each level of refinement, h --> h/2 and sum --> sum/2 */
159129f144ccSMatthew G. Knepley     mpfr_set(psum, osum, MPFR_RNDN);
159229f144ccSMatthew G. Knepley     mpfr_set(osum,  sum, MPFR_RNDN);
159329f144ccSMatthew G. Knepley     mpfr_mul_d(h,   h,   0.5, MPFR_RNDN);
159429f144ccSMatthew G. Knepley     mpfr_mul_d(sum, sum, 0.5, MPFR_RNDN);
159529f144ccSMatthew G. Knepley     do {
159629f144ccSMatthew G. Knepley       mpfr_set_si(kh, k, MPFR_RNDN);
159729f144ccSMatthew G. Knepley       mpfr_mul(kh, kh, h, MPFR_RNDN);
159829f144ccSMatthew G. Knepley       /* Weight */
159929f144ccSMatthew G. Knepley       mpfr_set(wk, h, MPFR_RNDN);
160029f144ccSMatthew G. Knepley       mpfr_sinh_cosh(msinh, mcosh, kh, MPFR_RNDN);
160129f144ccSMatthew G. Knepley       mpfr_mul(msinh, msinh, pi2, MPFR_RNDN);
160229f144ccSMatthew G. Knepley       mpfr_mul(mcosh, mcosh, pi2, MPFR_RNDN);
160329f144ccSMatthew G. Knepley       mpfr_cosh(tmp, msinh, MPFR_RNDN);
160429f144ccSMatthew G. Knepley       mpfr_sqr(tmp, tmp, MPFR_RNDN);
160529f144ccSMatthew G. Knepley       mpfr_mul(wk, wk, mcosh, MPFR_RNDN);
160629f144ccSMatthew G. Knepley       mpfr_div(wk, wk, tmp, MPFR_RNDN);
160729f144ccSMatthew G. Knepley       /* Abscissa */
160829f144ccSMatthew G. Knepley       mpfr_set_d(yk, 1.0, MPFR_RNDZ);
160929f144ccSMatthew G. Knepley       mpfr_cosh(tmp, msinh, MPFR_RNDN);
161029f144ccSMatthew G. Knepley       mpfr_div(yk, yk, tmp, MPFR_RNDZ);
161129f144ccSMatthew G. Knepley       mpfr_exp(tmp, msinh, MPFR_RNDN);
161229f144ccSMatthew G. Knepley       mpfr_div(yk, yk, tmp, MPFR_RNDZ);
161329f144ccSMatthew G. Knepley       /* Quadrature points */
161429f144ccSMatthew G. Knepley       mpfr_sub_d(lx, yk, 1.0, MPFR_RNDZ);
161529f144ccSMatthew G. Knepley       mpfr_mul(lx, lx, alpha, MPFR_RNDU);
161629f144ccSMatthew G. Knepley       mpfr_add(lx, lx, beta, MPFR_RNDU);
161729f144ccSMatthew G. Knepley       mpfr_d_sub(rx, 1.0, yk, MPFR_RNDZ);
161829f144ccSMatthew G. Knepley       mpfr_mul(rx, rx, alpha, MPFR_RNDD);
161929f144ccSMatthew G. Knepley       mpfr_add(rx, rx, beta, MPFR_RNDD);
162029f144ccSMatthew G. Knepley       /* Evaluation */
162129f144ccSMatthew G. Knepley       func(mpfr_get_d(lx, MPFR_RNDU), &lval);
162229f144ccSMatthew G. Knepley       func(mpfr_get_d(rx, MPFR_RNDD), &rval);
162329f144ccSMatthew G. Knepley       /* Update */
162429f144ccSMatthew G. Knepley       mpfr_mul(tmp, wk, alpha, MPFR_RNDN);
162529f144ccSMatthew G. Knepley       mpfr_mul_d(tmp, tmp, lval, MPFR_RNDN);
162629f144ccSMatthew G. Knepley       mpfr_add(sum, sum, tmp, MPFR_RNDN);
162729f144ccSMatthew G. Knepley       mpfr_abs(tmp, tmp, MPFR_RNDN);
162829f144ccSMatthew G. Knepley       mpfr_max(maxTerm, maxTerm, tmp, MPFR_RNDN);
162929f144ccSMatthew G. Knepley       mpfr_set(curTerm, tmp, MPFR_RNDN);
163029f144ccSMatthew G. Knepley       mpfr_mul(tmp, wk, alpha, MPFR_RNDN);
163129f144ccSMatthew G. Knepley       mpfr_mul_d(tmp, tmp, rval, MPFR_RNDN);
163229f144ccSMatthew G. Knepley       mpfr_add(sum, sum, tmp, MPFR_RNDN);
163329f144ccSMatthew G. Knepley       mpfr_abs(tmp, tmp, MPFR_RNDN);
163429f144ccSMatthew G. Knepley       mpfr_max(maxTerm, maxTerm, tmp, MPFR_RNDN);
163529f144ccSMatthew G. Knepley       mpfr_max(curTerm, curTerm, tmp, MPFR_RNDN);
163629f144ccSMatthew G. Knepley       ++k;
163729f144ccSMatthew G. Knepley       /* Only need to evaluate every other point on refined levels */
163829f144ccSMatthew G. Knepley       if (l != 1) ++k;
163929f144ccSMatthew G. Knepley       mpfr_log10(tmp, wk, MPFR_RNDN);
164029f144ccSMatthew G. Knepley       mpfr_abs(tmp, tmp, MPFR_RNDN);
1641c9f744b5SMatthew G. Knepley     } while (mpfr_get_d(tmp, MPFR_RNDN) < safetyFactor*digits); /* Only need to evaluate sum until weights are < 32 digits of precision */
164229f144ccSMatthew G. Knepley     mpfr_sub(tmp, sum, osum, MPFR_RNDN);
164329f144ccSMatthew G. Knepley     mpfr_abs(tmp, tmp, MPFR_RNDN);
164429f144ccSMatthew G. Knepley     mpfr_log10(tmp, tmp, MPFR_RNDN);
164529f144ccSMatthew G. Knepley     d1 = mpfr_get_d(tmp, MPFR_RNDN);
164629f144ccSMatthew G. Knepley     mpfr_sub(tmp, sum, psum, MPFR_RNDN);
164729f144ccSMatthew G. Knepley     mpfr_abs(tmp, tmp, MPFR_RNDN);
164829f144ccSMatthew G. Knepley     mpfr_log10(tmp, tmp, MPFR_RNDN);
164929f144ccSMatthew G. Knepley     d2 = mpfr_get_d(tmp, MPFR_RNDN);
165029f144ccSMatthew G. Knepley     mpfr_log10(tmp, maxTerm, MPFR_RNDN);
1651c9f744b5SMatthew G. Knepley     d3 = mpfr_get_d(tmp, MPFR_RNDN) - digits;
165229f144ccSMatthew G. Knepley     mpfr_log10(tmp, curTerm, MPFR_RNDN);
165329f144ccSMatthew G. Knepley     d4 = mpfr_get_d(tmp, MPFR_RNDN);
165429f144ccSMatthew G. Knepley     d  = PetscAbsInt(PetscMin(0, PetscMax(PetscMax(PetscMax(PetscSqr(d1)/d2, 2*d1), d3), d4)));
1655b0649871SThomas Klotz   } while (d < digits && l < 8);
165629f144ccSMatthew G. Knepley   *sol = mpfr_get_d(sum, MPFR_RNDN);
165729f144ccSMatthew G. Knepley   /* Cleanup */
165829f144ccSMatthew G. Knepley   mpfr_clears(alpha, beta, h, sum, osum, psum, yk, wk, lx, rx, tmp, maxTerm, curTerm, pi2, kh, msinh, mcosh, NULL);
165929f144ccSMatthew G. Knepley   PetscFunctionReturn(0);
166029f144ccSMatthew G. Knepley }
1661d525116cSMatthew G. Knepley #else
1662fbfcfee5SBarry Smith 
1663d525116cSMatthew G. Knepley PetscErrorCode PetscDTTanhSinhIntegrateMPFR(void (*func)(PetscReal, PetscReal *), PetscReal a, PetscReal b, PetscInt digits, PetscReal *sol)
1664d525116cSMatthew G. Knepley {
1665d525116cSMatthew G. Knepley   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "This method will not work without MPFR. Reconfigure using --download-mpfr --download-gmp");
1666d525116cSMatthew G. Knepley }
166729f144ccSMatthew G. Knepley #endif
166829f144ccSMatthew G. Knepley 
1669194825f6SJed Brown /* Overwrites A. Can only handle full-rank problems with m>=n
1670194825f6SJed Brown  * A in column-major format
1671194825f6SJed Brown  * Ainv in row-major format
1672194825f6SJed Brown  * tau has length m
1673194825f6SJed Brown  * worksize must be >= max(1,n)
1674194825f6SJed Brown  */
1675194825f6SJed Brown static PetscErrorCode PetscDTPseudoInverseQR(PetscInt m,PetscInt mstride,PetscInt n,PetscReal *A_in,PetscReal *Ainv_out,PetscScalar *tau,PetscInt worksize,PetscScalar *work)
1676194825f6SJed Brown {
1677194825f6SJed Brown   PetscErrorCode ierr;
1678194825f6SJed Brown   PetscBLASInt   M,N,K,lda,ldb,ldwork,info;
1679194825f6SJed Brown   PetscScalar    *A,*Ainv,*R,*Q,Alpha;
1680194825f6SJed Brown 
1681194825f6SJed Brown   PetscFunctionBegin;
1682194825f6SJed Brown #if defined(PETSC_USE_COMPLEX)
1683194825f6SJed Brown   {
1684194825f6SJed Brown     PetscInt i,j;
1685dcca6d9dSJed Brown     ierr = PetscMalloc2(m*n,&A,m*n,&Ainv);CHKERRQ(ierr);
1686194825f6SJed Brown     for (j=0; j<n; j++) {
1687194825f6SJed Brown       for (i=0; i<m; i++) A[i+m*j] = A_in[i+mstride*j];
1688194825f6SJed Brown     }
1689194825f6SJed Brown     mstride = m;
1690194825f6SJed Brown   }
1691194825f6SJed Brown #else
1692194825f6SJed Brown   A = A_in;
1693194825f6SJed Brown   Ainv = Ainv_out;
1694194825f6SJed Brown #endif
1695194825f6SJed Brown 
1696194825f6SJed Brown   ierr = PetscBLASIntCast(m,&M);CHKERRQ(ierr);
1697194825f6SJed Brown   ierr = PetscBLASIntCast(n,&N);CHKERRQ(ierr);
1698194825f6SJed Brown   ierr = PetscBLASIntCast(mstride,&lda);CHKERRQ(ierr);
1699194825f6SJed Brown   ierr = PetscBLASIntCast(worksize,&ldwork);CHKERRQ(ierr);
1700194825f6SJed Brown   ierr = PetscFPTrapPush(PETSC_FP_TRAP_OFF);CHKERRQ(ierr);
1701001a771dSBarry Smith   PetscStackCallBLAS("LAPACKgeqrf",LAPACKgeqrf_(&M,&N,A,&lda,tau,work,&ldwork,&info));
1702194825f6SJed Brown   ierr = PetscFPTrapPop();CHKERRQ(ierr);
1703194825f6SJed Brown   if (info) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"xGEQRF error");
1704194825f6SJed Brown   R = A; /* Upper triangular part of A now contains R, the rest contains the elementary reflectors */
1705194825f6SJed Brown 
1706194825f6SJed Brown   /* Extract an explicit representation of Q */
1707194825f6SJed Brown   Q = Ainv;
1708580bdb30SBarry Smith   ierr = PetscArraycpy(Q,A,mstride*n);CHKERRQ(ierr);
1709194825f6SJed Brown   K = N;                        /* full rank */
1710c964aadfSJose E. Roman   PetscStackCallBLAS("LAPACKorgqr",LAPACKorgqr_(&M,&N,&K,Q,&lda,tau,work,&ldwork,&info));
1711194825f6SJed Brown   if (info) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"xORGQR/xUNGQR error");
1712194825f6SJed Brown 
1713194825f6SJed Brown   /* Compute A^{-T} = (R^{-1} Q^T)^T = Q R^{-T} */
1714194825f6SJed Brown   Alpha = 1.0;
1715194825f6SJed Brown   ldb = lda;
1716001a771dSBarry Smith   PetscStackCallBLAS("BLAStrsm",BLAStrsm_("Right","Upper","ConjugateTranspose","NotUnitTriangular",&M,&N,&Alpha,R,&lda,Q,&ldb));
1717194825f6SJed Brown   /* Ainv is Q, overwritten with inverse */
1718194825f6SJed Brown 
1719194825f6SJed Brown #if defined(PETSC_USE_COMPLEX)
1720194825f6SJed Brown   {
1721194825f6SJed Brown     PetscInt i;
1722194825f6SJed Brown     for (i=0; i<m*n; i++) Ainv_out[i] = PetscRealPart(Ainv[i]);
1723194825f6SJed Brown     ierr = PetscFree2(A,Ainv);CHKERRQ(ierr);
1724194825f6SJed Brown   }
1725194825f6SJed Brown #endif
1726194825f6SJed Brown   PetscFunctionReturn(0);
1727194825f6SJed Brown }
1728194825f6SJed Brown 
1729194825f6SJed Brown /* Computes integral of L_p' over intervals {(x0,x1),(x1,x2),...} */
1730194825f6SJed Brown static PetscErrorCode PetscDTLegendreIntegrate(PetscInt ninterval,const PetscReal *x,PetscInt ndegree,const PetscInt *degrees,PetscBool Transpose,PetscReal *B)
1731194825f6SJed Brown {
1732194825f6SJed Brown   PetscErrorCode ierr;
1733194825f6SJed Brown   PetscReal      *Bv;
1734194825f6SJed Brown   PetscInt       i,j;
1735194825f6SJed Brown 
1736194825f6SJed Brown   PetscFunctionBegin;
1737785e854fSJed Brown   ierr = PetscMalloc1((ninterval+1)*ndegree,&Bv);CHKERRQ(ierr);
1738194825f6SJed Brown   /* Point evaluation of L_p on all the source vertices */
1739194825f6SJed Brown   ierr = PetscDTLegendreEval(ninterval+1,x,ndegree,degrees,Bv,NULL,NULL);CHKERRQ(ierr);
1740194825f6SJed Brown   /* Integral over each interval: \int_a^b L_p' = L_p(b)-L_p(a) */
1741194825f6SJed Brown   for (i=0; i<ninterval; i++) {
1742194825f6SJed Brown     for (j=0; j<ndegree; j++) {
1743194825f6SJed Brown       if (Transpose) B[i+ninterval*j] = Bv[(i+1)*ndegree+j] - Bv[i*ndegree+j];
1744194825f6SJed Brown       else           B[i*ndegree+j]   = Bv[(i+1)*ndegree+j] - Bv[i*ndegree+j];
1745194825f6SJed Brown     }
1746194825f6SJed Brown   }
1747194825f6SJed Brown   ierr = PetscFree(Bv);CHKERRQ(ierr);
1748194825f6SJed Brown   PetscFunctionReturn(0);
1749194825f6SJed Brown }
1750194825f6SJed Brown 
1751194825f6SJed Brown /*@
1752194825f6SJed Brown    PetscDTReconstructPoly - create matrix representing polynomial reconstruction using cell intervals and evaluation at target intervals
1753194825f6SJed Brown 
1754194825f6SJed Brown    Not Collective
1755194825f6SJed Brown 
1756194825f6SJed Brown    Input Arguments:
1757194825f6SJed Brown +  degree - degree of reconstruction polynomial
1758194825f6SJed Brown .  nsource - number of source intervals
1759194825f6SJed Brown .  sourcex - sorted coordinates of source cell boundaries (length nsource+1)
1760194825f6SJed Brown .  ntarget - number of target intervals
1761194825f6SJed Brown -  targetx - sorted coordinates of target cell boundaries (length ntarget+1)
1762194825f6SJed Brown 
1763194825f6SJed Brown    Output Arguments:
1764194825f6SJed Brown .  R - reconstruction matrix, utarget = sum_s R[t*nsource+s] * usource[s]
1765194825f6SJed Brown 
1766194825f6SJed Brown    Level: advanced
1767194825f6SJed Brown 
1768194825f6SJed Brown .seealso: PetscDTLegendreEval()
1769194825f6SJed Brown @*/
1770194825f6SJed Brown PetscErrorCode PetscDTReconstructPoly(PetscInt degree,PetscInt nsource,const PetscReal *sourcex,PetscInt ntarget,const PetscReal *targetx,PetscReal *R)
1771194825f6SJed Brown {
1772194825f6SJed Brown   PetscErrorCode ierr;
1773194825f6SJed Brown   PetscInt       i,j,k,*bdegrees,worksize;
1774194825f6SJed Brown   PetscReal      xmin,xmax,center,hscale,*sourcey,*targety,*Bsource,*Bsinv,*Btarget;
1775194825f6SJed Brown   PetscScalar    *tau,*work;
1776194825f6SJed Brown 
1777194825f6SJed Brown   PetscFunctionBegin;
1778194825f6SJed Brown   PetscValidRealPointer(sourcex,3);
1779194825f6SJed Brown   PetscValidRealPointer(targetx,5);
1780194825f6SJed Brown   PetscValidRealPointer(R,6);
1781194825f6SJed 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);
1782194825f6SJed Brown #if defined(PETSC_USE_DEBUG)
1783194825f6SJed Brown   for (i=0; i<nsource; i++) {
178457622a8eSBarry 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]);
1785194825f6SJed Brown   }
1786194825f6SJed Brown   for (i=0; i<ntarget; i++) {
178757622a8eSBarry 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]);
1788194825f6SJed Brown   }
1789194825f6SJed Brown #endif
1790194825f6SJed Brown   xmin = PetscMin(sourcex[0],targetx[0]);
1791194825f6SJed Brown   xmax = PetscMax(sourcex[nsource],targetx[ntarget]);
1792194825f6SJed Brown   center = (xmin + xmax)/2;
1793194825f6SJed Brown   hscale = (xmax - xmin)/2;
1794194825f6SJed Brown   worksize = nsource;
1795dcca6d9dSJed Brown   ierr = PetscMalloc4(degree+1,&bdegrees,nsource+1,&sourcey,nsource*(degree+1),&Bsource,worksize,&work);CHKERRQ(ierr);
1796dcca6d9dSJed Brown   ierr = PetscMalloc4(nsource,&tau,nsource*(degree+1),&Bsinv,ntarget+1,&targety,ntarget*(degree+1),&Btarget);CHKERRQ(ierr);
1797194825f6SJed Brown   for (i=0; i<=nsource; i++) sourcey[i] = (sourcex[i]-center)/hscale;
1798194825f6SJed Brown   for (i=0; i<=degree; i++) bdegrees[i] = i+1;
1799194825f6SJed Brown   ierr = PetscDTLegendreIntegrate(nsource,sourcey,degree+1,bdegrees,PETSC_TRUE,Bsource);CHKERRQ(ierr);
1800194825f6SJed Brown   ierr = PetscDTPseudoInverseQR(nsource,nsource,degree+1,Bsource,Bsinv,tau,nsource,work);CHKERRQ(ierr);
1801194825f6SJed Brown   for (i=0; i<=ntarget; i++) targety[i] = (targetx[i]-center)/hscale;
1802194825f6SJed Brown   ierr = PetscDTLegendreIntegrate(ntarget,targety,degree+1,bdegrees,PETSC_FALSE,Btarget);CHKERRQ(ierr);
1803194825f6SJed Brown   for (i=0; i<ntarget; i++) {
1804194825f6SJed Brown     PetscReal rowsum = 0;
1805194825f6SJed Brown     for (j=0; j<nsource; j++) {
1806194825f6SJed Brown       PetscReal sum = 0;
1807194825f6SJed Brown       for (k=0; k<degree+1; k++) {
1808194825f6SJed Brown         sum += Btarget[i*(degree+1)+k] * Bsinv[k*nsource+j];
1809194825f6SJed Brown       }
1810194825f6SJed Brown       R[i*nsource+j] = sum;
1811194825f6SJed Brown       rowsum += sum;
1812194825f6SJed Brown     }
1813194825f6SJed Brown     for (j=0; j<nsource; j++) R[i*nsource+j] /= rowsum; /* normalize each row */
1814194825f6SJed Brown   }
1815194825f6SJed Brown   ierr = PetscFree4(bdegrees,sourcey,Bsource,work);CHKERRQ(ierr);
1816194825f6SJed Brown   ierr = PetscFree4(tau,Bsinv,targety,Btarget);CHKERRQ(ierr);
1817194825f6SJed Brown   PetscFunctionReturn(0);
1818194825f6SJed Brown }
1819916e780bShannah_mairs 
1820916e780bShannah_mairs /*@C
1821916e780bShannah_mairs    PetscGaussLobattoLegendreIntegrate - Compute the L2 integral of a function on the GLL points
1822916e780bShannah_mairs 
1823916e780bShannah_mairs    Not Collective
1824916e780bShannah_mairs 
1825916e780bShannah_mairs    Input Parameter:
1826916e780bShannah_mairs +  n - the number of GLL nodes
1827916e780bShannah_mairs .  nodes - the GLL nodes
1828916e780bShannah_mairs .  weights - the GLL weights
1829*f0fc11ceSJed Brown -  f - the function values at the nodes
1830916e780bShannah_mairs 
1831916e780bShannah_mairs    Output Parameter:
1832916e780bShannah_mairs .  in - the value of the integral
1833916e780bShannah_mairs 
1834916e780bShannah_mairs    Level: beginner
1835916e780bShannah_mairs 
1836916e780bShannah_mairs .seealso: PetscDTGaussLobattoLegendreQuadrature()
1837916e780bShannah_mairs 
1838916e780bShannah_mairs @*/
1839916e780bShannah_mairs PetscErrorCode PetscGaussLobattoLegendreIntegrate(PetscInt n,PetscReal *nodes,PetscReal *weights,const PetscReal *f,PetscReal *in)
1840916e780bShannah_mairs {
1841916e780bShannah_mairs   PetscInt          i;
1842916e780bShannah_mairs 
1843916e780bShannah_mairs   PetscFunctionBegin;
1844916e780bShannah_mairs   *in = 0.;
1845916e780bShannah_mairs   for (i=0; i<n; i++) {
1846916e780bShannah_mairs     *in += f[i]*f[i]*weights[i];
1847916e780bShannah_mairs   }
1848916e780bShannah_mairs   PetscFunctionReturn(0);
1849916e780bShannah_mairs }
1850916e780bShannah_mairs 
1851916e780bShannah_mairs /*@C
1852916e780bShannah_mairs    PetscGaussLobattoLegendreElementLaplacianCreate - computes the Laplacian for a single 1d GLL element
1853916e780bShannah_mairs 
1854916e780bShannah_mairs    Not Collective
1855916e780bShannah_mairs 
1856916e780bShannah_mairs    Input Parameter:
1857916e780bShannah_mairs +  n - the number of GLL nodes
1858916e780bShannah_mairs .  nodes - the GLL nodes
1859*f0fc11ceSJed Brown -  weights - the GLL weights
1860916e780bShannah_mairs 
1861916e780bShannah_mairs    Output Parameter:
1862916e780bShannah_mairs .  A - the stiffness element
1863916e780bShannah_mairs 
1864916e780bShannah_mairs    Level: beginner
1865916e780bShannah_mairs 
1866916e780bShannah_mairs    Notes:
1867916e780bShannah_mairs     Destroy this with PetscGaussLobattoLegendreElementLaplacianDestroy()
1868916e780bShannah_mairs 
1869916e780bShannah_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)
1870916e780bShannah_mairs 
1871916e780bShannah_mairs .seealso: PetscDTGaussLobattoLegendreQuadrature(), PetscGaussLobattoLegendreElementLaplacianDestroy()
1872916e780bShannah_mairs 
1873916e780bShannah_mairs @*/
1874916e780bShannah_mairs PetscErrorCode PetscGaussLobattoLegendreElementLaplacianCreate(PetscInt n,PetscReal *nodes,PetscReal *weights,PetscReal ***AA)
1875916e780bShannah_mairs {
1876916e780bShannah_mairs   PetscReal        **A;
1877916e780bShannah_mairs   PetscErrorCode  ierr;
1878916e780bShannah_mairs   const PetscReal  *gllnodes = nodes;
1879916e780bShannah_mairs   const PetscInt   p = n-1;
1880916e780bShannah_mairs   PetscReal        z0,z1,z2 = -1,x,Lpj,Lpr;
1881916e780bShannah_mairs   PetscInt         i,j,nn,r;
1882916e780bShannah_mairs 
1883916e780bShannah_mairs   PetscFunctionBegin;
1884916e780bShannah_mairs   ierr = PetscMalloc1(n,&A);CHKERRQ(ierr);
1885916e780bShannah_mairs   ierr = PetscMalloc1(n*n,&A[0]);CHKERRQ(ierr);
1886916e780bShannah_mairs   for (i=1; i<n; i++) A[i] = A[i-1]+n;
1887916e780bShannah_mairs 
1888916e780bShannah_mairs   for (j=1; j<p; j++) {
1889916e780bShannah_mairs     x  = gllnodes[j];
1890916e780bShannah_mairs     z0 = 1.;
1891916e780bShannah_mairs     z1 = x;
1892916e780bShannah_mairs     for (nn=1; nn<p; nn++) {
1893916e780bShannah_mairs       z2 = x*z1*(2.*((PetscReal)nn)+1.)/(((PetscReal)nn)+1.)-z0*(((PetscReal)nn)/(((PetscReal)nn)+1.));
1894916e780bShannah_mairs       z0 = z1;
1895916e780bShannah_mairs       z1 = z2;
1896916e780bShannah_mairs     }
1897916e780bShannah_mairs     Lpj=z2;
1898916e780bShannah_mairs     for (r=1; r<p; r++) {
1899916e780bShannah_mairs       if (r == j) {
1900916e780bShannah_mairs         A[j][j]=2./(3.*(1.-gllnodes[j]*gllnodes[j])*Lpj*Lpj);
1901916e780bShannah_mairs       } else {
1902916e780bShannah_mairs         x  = gllnodes[r];
1903916e780bShannah_mairs         z0 = 1.;
1904916e780bShannah_mairs         z1 = x;
1905916e780bShannah_mairs         for (nn=1; nn<p; nn++) {
1906916e780bShannah_mairs           z2 = x*z1*(2.*((PetscReal)nn)+1.)/(((PetscReal)nn)+1.)-z0*(((PetscReal)nn)/(((PetscReal)nn)+1.));
1907916e780bShannah_mairs           z0 = z1;
1908916e780bShannah_mairs           z1 = z2;
1909916e780bShannah_mairs         }
1910916e780bShannah_mairs         Lpr     = z2;
1911916e780bShannah_mairs         A[r][j] = 4./(((PetscReal)p)*(((PetscReal)p)+1.)*Lpj*Lpr*(gllnodes[j]-gllnodes[r])*(gllnodes[j]-gllnodes[r]));
1912916e780bShannah_mairs       }
1913916e780bShannah_mairs     }
1914916e780bShannah_mairs   }
1915916e780bShannah_mairs   for (j=1; j<p+1; j++) {
1916916e780bShannah_mairs     x  = gllnodes[j];
1917916e780bShannah_mairs     z0 = 1.;
1918916e780bShannah_mairs     z1 = x;
1919916e780bShannah_mairs     for (nn=1; nn<p; nn++) {
1920916e780bShannah_mairs       z2 = x*z1*(2.*((PetscReal)nn)+1.)/(((PetscReal)nn)+1.)-z0*(((PetscReal)nn)/(((PetscReal)nn)+1.));
1921916e780bShannah_mairs       z0 = z1;
1922916e780bShannah_mairs       z1 = z2;
1923916e780bShannah_mairs     }
1924916e780bShannah_mairs     Lpj     = z2;
1925916e780bShannah_mairs     A[j][0] = 4.*PetscPowRealInt(-1.,p)/(((PetscReal)p)*(((PetscReal)p)+1.)*Lpj*(1.+gllnodes[j])*(1.+gllnodes[j]));
1926916e780bShannah_mairs     A[0][j] = A[j][0];
1927916e780bShannah_mairs   }
1928916e780bShannah_mairs   for (j=0; j<p; j++) {
1929916e780bShannah_mairs     x  = gllnodes[j];
1930916e780bShannah_mairs     z0 = 1.;
1931916e780bShannah_mairs     z1 = x;
1932916e780bShannah_mairs     for (nn=1; nn<p; nn++) {
1933916e780bShannah_mairs       z2 = x*z1*(2.*((PetscReal)nn)+1.)/(((PetscReal)nn)+1.)-z0*(((PetscReal)nn)/(((PetscReal)nn)+1.));
1934916e780bShannah_mairs       z0 = z1;
1935916e780bShannah_mairs       z1 = z2;
1936916e780bShannah_mairs     }
1937916e780bShannah_mairs     Lpj=z2;
1938916e780bShannah_mairs 
1939916e780bShannah_mairs     A[p][j] = 4./(((PetscReal)p)*(((PetscReal)p)+1.)*Lpj*(1.-gllnodes[j])*(1.-gllnodes[j]));
1940916e780bShannah_mairs     A[j][p] = A[p][j];
1941916e780bShannah_mairs   }
1942916e780bShannah_mairs   A[0][0]=0.5+(((PetscReal)p)*(((PetscReal)p)+1.)-2.)/6.;
1943916e780bShannah_mairs   A[p][p]=A[0][0];
1944916e780bShannah_mairs   *AA = A;
1945916e780bShannah_mairs   PetscFunctionReturn(0);
1946916e780bShannah_mairs }
1947916e780bShannah_mairs 
1948916e780bShannah_mairs /*@C
1949916e780bShannah_mairs    PetscGaussLobattoLegendreElementLaplacianDestroy - frees the Laplacian for a single 1d GLL element
1950916e780bShannah_mairs 
1951916e780bShannah_mairs    Not Collective
1952916e780bShannah_mairs 
1953916e780bShannah_mairs    Input Parameter:
1954916e780bShannah_mairs +  n - the number of GLL nodes
1955916e780bShannah_mairs .  nodes - the GLL nodes
1956916e780bShannah_mairs .  weights - the GLL weightss
1957916e780bShannah_mairs -  A - the stiffness element
1958916e780bShannah_mairs 
1959916e780bShannah_mairs    Level: beginner
1960916e780bShannah_mairs 
1961916e780bShannah_mairs .seealso: PetscDTGaussLobattoLegendreQuadrature(), PetscGaussLobattoLegendreElementLaplacianCreate()
1962916e780bShannah_mairs 
1963916e780bShannah_mairs @*/
1964916e780bShannah_mairs PetscErrorCode PetscGaussLobattoLegendreElementLaplacianDestroy(PetscInt n,PetscReal *nodes,PetscReal *weights,PetscReal ***AA)
1965916e780bShannah_mairs {
1966916e780bShannah_mairs   PetscErrorCode ierr;
1967916e780bShannah_mairs 
1968916e780bShannah_mairs   PetscFunctionBegin;
1969916e780bShannah_mairs   ierr = PetscFree((*AA)[0]);CHKERRQ(ierr);
1970916e780bShannah_mairs   ierr = PetscFree(*AA);CHKERRQ(ierr);
1971916e780bShannah_mairs   *AA  = NULL;
1972916e780bShannah_mairs   PetscFunctionReturn(0);
1973916e780bShannah_mairs }
1974916e780bShannah_mairs 
1975916e780bShannah_mairs /*@C
1976916e780bShannah_mairs    PetscGaussLobattoLegendreElementGradientCreate - computes the gradient for a single 1d GLL element
1977916e780bShannah_mairs 
1978916e780bShannah_mairs    Not Collective
1979916e780bShannah_mairs 
1980916e780bShannah_mairs    Input Parameter:
1981916e780bShannah_mairs +  n - the number of GLL nodes
1982916e780bShannah_mairs .  nodes - the GLL nodes
1983916e780bShannah_mairs .  weights - the GLL weights
1984916e780bShannah_mairs 
1985916e780bShannah_mairs    Output Parameter:
1986916e780bShannah_mairs .  AA - the stiffness element
1987916e780bShannah_mairs -  AAT - the transpose of AA (pass in NULL if you do not need this array)
1988916e780bShannah_mairs 
1989916e780bShannah_mairs    Level: beginner
1990916e780bShannah_mairs 
1991916e780bShannah_mairs    Notes:
1992916e780bShannah_mairs     Destroy this with PetscGaussLobattoLegendreElementGradientDestroy()
1993916e780bShannah_mairs 
1994916e780bShannah_mairs    You can access entries in these arrays with AA[i][j] but in memory it is stored in contiguous memory, row oriented
1995916e780bShannah_mairs 
1996916e780bShannah_mairs .seealso: PetscDTGaussLobattoLegendreQuadrature(), PetscGaussLobattoLegendreElementLaplacianDestroy()
1997916e780bShannah_mairs 
1998916e780bShannah_mairs @*/
1999916e780bShannah_mairs PetscErrorCode PetscGaussLobattoLegendreElementGradientCreate(PetscInt n,PetscReal *nodes,PetscReal *weights,PetscReal ***AA,PetscReal ***AAT)
2000916e780bShannah_mairs {
2001916e780bShannah_mairs   PetscReal        **A, **AT = NULL;
2002916e780bShannah_mairs   PetscErrorCode  ierr;
2003916e780bShannah_mairs   const PetscReal  *gllnodes = nodes;
2004916e780bShannah_mairs   const PetscInt   p = n-1;
2005e6a796c3SToby Isaac   PetscReal        Li, Lj,d0;
2006916e780bShannah_mairs   PetscInt         i,j;
2007916e780bShannah_mairs 
2008916e780bShannah_mairs   PetscFunctionBegin;
2009916e780bShannah_mairs   ierr = PetscMalloc1(n,&A);CHKERRQ(ierr);
2010916e780bShannah_mairs   ierr = PetscMalloc1(n*n,&A[0]);CHKERRQ(ierr);
2011916e780bShannah_mairs   for (i=1; i<n; i++) A[i] = A[i-1]+n;
2012916e780bShannah_mairs 
2013916e780bShannah_mairs   if (AAT) {
2014916e780bShannah_mairs     ierr = PetscMalloc1(n,&AT);CHKERRQ(ierr);
2015916e780bShannah_mairs     ierr = PetscMalloc1(n*n,&AT[0]);CHKERRQ(ierr);
2016916e780bShannah_mairs     for (i=1; i<n; i++) AT[i] = AT[i-1]+n;
2017916e780bShannah_mairs   }
2018916e780bShannah_mairs 
2019916e780bShannah_mairs   if (n==1) {A[0][0] = 0.;}
2020916e780bShannah_mairs   d0 = (PetscReal)p*((PetscReal)p+1.)/4.;
2021916e780bShannah_mairs   for  (i=0; i<n; i++) {
2022916e780bShannah_mairs     for  (j=0; j<n; j++) {
2023916e780bShannah_mairs       A[i][j] = 0.;
2024e6a796c3SToby Isaac       ierr = PetscDTComputeJacobi(0., 0., p, gllnodes[i], &Li);CHKERRQ(ierr);
2025e6a796c3SToby Isaac       ierr = PetscDTComputeJacobi(0., 0., p, gllnodes[j], &Lj);CHKERRQ(ierr);
2026916e780bShannah_mairs       if (i!=j)             A[i][j] = Li/(Lj*(gllnodes[i]-gllnodes[j]));
2027916e780bShannah_mairs       if ((j==i) && (i==0)) A[i][j] = -d0;
2028916e780bShannah_mairs       if (j==i && i==p)     A[i][j] = d0;
2029916e780bShannah_mairs       if (AT) AT[j][i] = A[i][j];
2030916e780bShannah_mairs     }
2031916e780bShannah_mairs   }
2032916e780bShannah_mairs   if (AAT) *AAT = AT;
2033916e780bShannah_mairs   *AA  = A;
2034916e780bShannah_mairs   PetscFunctionReturn(0);
2035916e780bShannah_mairs }
2036916e780bShannah_mairs 
2037916e780bShannah_mairs /*@C
2038916e780bShannah_mairs    PetscGaussLobattoLegendreElementGradientDestroy - frees the gradient for a single 1d GLL element obtained with PetscGaussLobattoLegendreElementGradientCreate()
2039916e780bShannah_mairs 
2040916e780bShannah_mairs    Not Collective
2041916e780bShannah_mairs 
2042916e780bShannah_mairs    Input Parameter:
2043916e780bShannah_mairs +  n - the number of GLL nodes
2044916e780bShannah_mairs .  nodes - the GLL nodes
2045916e780bShannah_mairs .  weights - the GLL weights
2046916e780bShannah_mairs .  AA - the stiffness element
2047916e780bShannah_mairs -  AAT - the transpose of the element
2048916e780bShannah_mairs 
2049916e780bShannah_mairs    Level: beginner
2050916e780bShannah_mairs 
2051916e780bShannah_mairs .seealso: PetscDTGaussLobattoLegendreQuadrature(), PetscGaussLobattoLegendreElementLaplacianCreate(), PetscGaussLobattoLegendreElementAdvectionCreate()
2052916e780bShannah_mairs 
2053916e780bShannah_mairs @*/
2054916e780bShannah_mairs PetscErrorCode PetscGaussLobattoLegendreElementGradientDestroy(PetscInt n,PetscReal *nodes,PetscReal *weights,PetscReal ***AA,PetscReal ***AAT)
2055916e780bShannah_mairs {
2056916e780bShannah_mairs   PetscErrorCode ierr;
2057916e780bShannah_mairs 
2058916e780bShannah_mairs   PetscFunctionBegin;
2059916e780bShannah_mairs   ierr = PetscFree((*AA)[0]);CHKERRQ(ierr);
2060916e780bShannah_mairs   ierr = PetscFree(*AA);CHKERRQ(ierr);
2061916e780bShannah_mairs   *AA  = NULL;
2062916e780bShannah_mairs   if (*AAT) {
2063916e780bShannah_mairs     ierr = PetscFree((*AAT)[0]);CHKERRQ(ierr);
2064916e780bShannah_mairs     ierr = PetscFree(*AAT);CHKERRQ(ierr);
2065916e780bShannah_mairs     *AAT  = NULL;
2066916e780bShannah_mairs   }
2067916e780bShannah_mairs   PetscFunctionReturn(0);
2068916e780bShannah_mairs }
2069916e780bShannah_mairs 
2070916e780bShannah_mairs /*@C
2071916e780bShannah_mairs    PetscGaussLobattoLegendreElementAdvectionCreate - computes the advection operator for a single 1d GLL element
2072916e780bShannah_mairs 
2073916e780bShannah_mairs    Not Collective
2074916e780bShannah_mairs 
2075916e780bShannah_mairs    Input Parameter:
2076916e780bShannah_mairs +  n - the number of GLL nodes
2077916e780bShannah_mairs .  nodes - the GLL nodes
2078*f0fc11ceSJed Brown -  weights - the GLL weightss
2079916e780bShannah_mairs 
2080916e780bShannah_mairs    Output Parameter:
2081916e780bShannah_mairs .  AA - the stiffness element
2082916e780bShannah_mairs 
2083916e780bShannah_mairs    Level: beginner
2084916e780bShannah_mairs 
2085916e780bShannah_mairs    Notes:
2086916e780bShannah_mairs     Destroy this with PetscGaussLobattoLegendreElementAdvectionDestroy()
2087916e780bShannah_mairs 
2088916e780bShannah_mairs    This is the same as the Gradient operator multiplied by the diagonal mass matrix
2089916e780bShannah_mairs 
2090916e780bShannah_mairs    You can access entries in this array with AA[i][j] but in memory it is stored in contiguous memory, row oriented
2091916e780bShannah_mairs 
2092916e780bShannah_mairs .seealso: PetscDTGaussLobattoLegendreQuadrature(), PetscGaussLobattoLegendreElementLaplacianCreate(), PetscGaussLobattoLegendreElementAdvectionDestroy()
2093916e780bShannah_mairs 
2094916e780bShannah_mairs @*/
2095916e780bShannah_mairs PetscErrorCode PetscGaussLobattoLegendreElementAdvectionCreate(PetscInt n,PetscReal *nodes,PetscReal *weights,PetscReal ***AA)
2096916e780bShannah_mairs {
2097916e780bShannah_mairs   PetscReal       **D;
2098916e780bShannah_mairs   PetscErrorCode  ierr;
2099916e780bShannah_mairs   const PetscReal  *gllweights = weights;
2100916e780bShannah_mairs   const PetscInt   glln = n;
2101916e780bShannah_mairs   PetscInt         i,j;
2102916e780bShannah_mairs 
2103916e780bShannah_mairs   PetscFunctionBegin;
2104916e780bShannah_mairs   ierr = PetscGaussLobattoLegendreElementGradientCreate(n,nodes,weights,&D,NULL);CHKERRQ(ierr);
2105916e780bShannah_mairs   for (i=0; i<glln; i++){
2106916e780bShannah_mairs     for (j=0; j<glln; j++) {
2107916e780bShannah_mairs       D[i][j] = gllweights[i]*D[i][j];
2108916e780bShannah_mairs     }
2109916e780bShannah_mairs   }
2110916e780bShannah_mairs   *AA = D;
2111916e780bShannah_mairs   PetscFunctionReturn(0);
2112916e780bShannah_mairs }
2113916e780bShannah_mairs 
2114916e780bShannah_mairs /*@C
2115916e780bShannah_mairs    PetscGaussLobattoLegendreElementAdvectionDestroy - frees the advection stiffness for a single 1d GLL element
2116916e780bShannah_mairs 
2117916e780bShannah_mairs    Not Collective
2118916e780bShannah_mairs 
2119916e780bShannah_mairs    Input Parameter:
2120916e780bShannah_mairs +  n - the number of GLL nodes
2121916e780bShannah_mairs .  nodes - the GLL nodes
2122916e780bShannah_mairs .  weights - the GLL weights
2123916e780bShannah_mairs -  A - advection
2124916e780bShannah_mairs 
2125916e780bShannah_mairs    Level: beginner
2126916e780bShannah_mairs 
2127916e780bShannah_mairs .seealso: PetscDTGaussLobattoLegendreQuadrature(), PetscGaussLobattoLegendreElementAdvectionCreate()
2128916e780bShannah_mairs 
2129916e780bShannah_mairs @*/
2130916e780bShannah_mairs PetscErrorCode PetscGaussLobattoLegendreElementAdvectionDestroy(PetscInt n,PetscReal *nodes,PetscReal *weights,PetscReal ***AA)
2131916e780bShannah_mairs {
2132916e780bShannah_mairs   PetscErrorCode ierr;
2133916e780bShannah_mairs 
2134916e780bShannah_mairs   PetscFunctionBegin;
2135916e780bShannah_mairs   ierr = PetscFree((*AA)[0]);CHKERRQ(ierr);
2136916e780bShannah_mairs   ierr = PetscFree(*AA);CHKERRQ(ierr);
2137916e780bShannah_mairs   *AA  = NULL;
2138916e780bShannah_mairs   PetscFunctionReturn(0);
2139916e780bShannah_mairs }
2140916e780bShannah_mairs 
2141916e780bShannah_mairs PetscErrorCode PetscGaussLobattoLegendreElementMassCreate(PetscInt n,PetscReal *nodes,PetscReal *weights,PetscReal ***AA)
2142916e780bShannah_mairs {
2143916e780bShannah_mairs   PetscReal        **A;
2144916e780bShannah_mairs   PetscErrorCode  ierr;
2145916e780bShannah_mairs   const PetscReal  *gllweights = weights;
2146916e780bShannah_mairs   const PetscInt   glln = n;
2147916e780bShannah_mairs   PetscInt         i,j;
2148916e780bShannah_mairs 
2149916e780bShannah_mairs   PetscFunctionBegin;
2150916e780bShannah_mairs   ierr = PetscMalloc1(glln,&A);CHKERRQ(ierr);
2151916e780bShannah_mairs   ierr = PetscMalloc1(glln*glln,&A[0]);CHKERRQ(ierr);
2152916e780bShannah_mairs   for (i=1; i<glln; i++) A[i] = A[i-1]+glln;
2153916e780bShannah_mairs   if (glln==1) {A[0][0] = 0.;}
2154916e780bShannah_mairs   for  (i=0; i<glln; i++) {
2155916e780bShannah_mairs     for  (j=0; j<glln; j++) {
2156916e780bShannah_mairs       A[i][j] = 0.;
2157916e780bShannah_mairs       if (j==i)     A[i][j] = gllweights[i];
2158916e780bShannah_mairs     }
2159916e780bShannah_mairs   }
2160916e780bShannah_mairs   *AA  = A;
2161916e780bShannah_mairs   PetscFunctionReturn(0);
2162916e780bShannah_mairs }
2163916e780bShannah_mairs 
2164916e780bShannah_mairs PetscErrorCode PetscGaussLobattoLegendreElementMassDestroy(PetscInt n,PetscReal *nodes,PetscReal *weights,PetscReal ***AA)
2165916e780bShannah_mairs {
2166916e780bShannah_mairs   PetscErrorCode ierr;
2167916e780bShannah_mairs 
2168916e780bShannah_mairs   PetscFunctionBegin;
2169916e780bShannah_mairs   ierr = PetscFree((*AA)[0]);CHKERRQ(ierr);
2170916e780bShannah_mairs   ierr = PetscFree(*AA);CHKERRQ(ierr);
2171916e780bShannah_mairs   *AA  = NULL;
2172916e780bShannah_mairs   PetscFunctionReturn(0);
2173916e780bShannah_mairs }
2174