xref: /petsc/src/dm/dt/fe/impls/basic/febasic.c (revision bfcb38ea38335faa6e7f8d97f6bc6ce9aa2a1dd1)
1 #include <petsc/private/petscfeimpl.h> /*I "petscfe.h" I*/
2 #include <petscblaslapack.h>
3 
4 PetscErrorCode PetscFEDestroy_Basic(PetscFE fem)
5 {
6   PetscFE_Basic *b = (PetscFE_Basic *) fem->data;
7   PetscErrorCode ierr;
8 
9   PetscFunctionBegin;
10   ierr = PetscFree(b);CHKERRQ(ierr);
11   PetscFunctionReturn(0);
12 }
13 
14 PetscErrorCode PetscFEView_Basic_Ascii(PetscFE fe, PetscViewer v)
15 {
16   PetscInt          dim, Nc;
17   PetscSpace        basis = NULL;
18   PetscDualSpace    dual = NULL;
19   PetscQuadrature   quad = NULL;
20   PetscErrorCode    ierr;
21 
22   PetscFunctionBegin;
23   ierr = PetscFEGetSpatialDimension(fe, &dim);CHKERRQ(ierr);
24   ierr = PetscFEGetNumComponents(fe, &Nc);CHKERRQ(ierr);
25   ierr = PetscFEGetBasisSpace(fe, &basis);CHKERRQ(ierr);
26   ierr = PetscFEGetDualSpace(fe, &dual);CHKERRQ(ierr);
27   ierr = PetscFEGetQuadrature(fe, &quad);CHKERRQ(ierr);
28   ierr = PetscViewerASCIIPushTab(v);CHKERRQ(ierr);
29   ierr = PetscViewerASCIIPrintf(v, "Basic Finite Element in %D dimensions with %D components\n",dim,Nc);CHKERRQ(ierr);
30   if (basis) {ierr = PetscSpaceView(basis, v);CHKERRQ(ierr);}
31   if (dual)  {ierr = PetscDualSpaceView(dual, v);CHKERRQ(ierr);}
32   if (quad)  {ierr = PetscQuadratureView(quad, v);CHKERRQ(ierr);}
33   ierr = PetscViewerASCIIPopTab(v);CHKERRQ(ierr);
34   PetscFunctionReturn(0);
35 }
36 
37 PetscErrorCode PetscFEView_Basic(PetscFE fe, PetscViewer v)
38 {
39   PetscBool      iascii;
40   PetscErrorCode ierr;
41 
42   PetscFunctionBegin;
43   ierr = PetscObjectTypeCompare((PetscObject) v, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
44   if (iascii) {ierr = PetscFEView_Basic_Ascii(fe, v);CHKERRQ(ierr);}
45   PetscFunctionReturn(0);
46 }
47 
48 /* Construct the change of basis from prime basis to nodal basis */
49 PetscErrorCode PetscFESetUp_Basic(PetscFE fem)
50 {
51   PetscScalar   *work, *invVscalar;
52   PetscBLASInt  *pivots;
53   PetscBLASInt   n, info;
54   PetscInt       pdim, j;
55   PetscErrorCode ierr;
56 
57   PetscFunctionBegin;
58   ierr = PetscDualSpaceGetDimension(fem->dualSpace, &pdim);CHKERRQ(ierr);
59   ierr = PetscMalloc1(pdim*pdim,&fem->invV);CHKERRQ(ierr);
60 #if defined(PETSC_USE_COMPLEX)
61   ierr = PetscMalloc1(pdim*pdim,&invVscalar);CHKERRQ(ierr);
62 #else
63   invVscalar = fem->invV;
64 #endif
65   for (j = 0; j < pdim; ++j) {
66     PetscReal       *Bf;
67     PetscQuadrature  f;
68     const PetscReal *points, *weights;
69     PetscInt         Nc, Nq, q, k, c;
70 
71     ierr = PetscDualSpaceGetFunctional(fem->dualSpace, j, &f);CHKERRQ(ierr);
72     ierr = PetscQuadratureGetData(f, NULL, &Nc, &Nq, &points, &weights);CHKERRQ(ierr);
73     ierr = PetscMalloc1(Nc*Nq*pdim,&Bf);CHKERRQ(ierr);
74     ierr = PetscSpaceEvaluate(fem->basisSpace, Nq, points, Bf, NULL, NULL);CHKERRQ(ierr);
75     for (k = 0; k < pdim; ++k) {
76       /* V_{jk} = n_j(\phi_k) = \int \phi_k(x) n_j(x) dx */
77       invVscalar[j*pdim+k] = 0.0;
78 
79       for (q = 0; q < Nq; ++q) {
80         for (c = 0; c < Nc; ++c) invVscalar[j*pdim+k] += Bf[(q*pdim + k)*Nc + c]*weights[q*Nc + c];
81       }
82     }
83     ierr = PetscFree(Bf);CHKERRQ(ierr);
84   }
85   ierr = PetscMalloc2(pdim,&pivots,pdim,&work);CHKERRQ(ierr);
86   n = pdim;
87   PetscStackCallBLAS("LAPACKgetrf", LAPACKgetrf_(&n, &n, invVscalar, &n, pivots, &info));
88   PetscStackCallBLAS("LAPACKgetri", LAPACKgetri_(&n, invVscalar, &n, pivots, work, &n, &info));
89 #if defined(PETSC_USE_COMPLEX)
90   for (j = 0; j < pdim*pdim; j++) fem->invV[j] = PetscRealPart(invVscalar[j]);
91   ierr = PetscFree(invVscalar);CHKERRQ(ierr);
92 #endif
93   ierr = PetscFree2(pivots,work);CHKERRQ(ierr);
94   PetscFunctionReturn(0);
95 }
96 
97 PetscErrorCode PetscFEGetDimension_Basic(PetscFE fem, PetscInt *dim)
98 {
99   PetscErrorCode ierr;
100 
101   PetscFunctionBegin;
102   ierr = PetscDualSpaceGetDimension(fem->dualSpace, dim);CHKERRQ(ierr);
103   PetscFunctionReturn(0);
104 }
105 
106 PetscErrorCode PetscFEGetTabulation_Basic(PetscFE fem, PetscInt npoints, const PetscReal points[], PetscReal *B, PetscReal *D, PetscReal *H)
107 {
108   DM               dm;
109   PetscInt         pdim; /* Dimension of FE space P */
110   PetscInt         dim;  /* Spatial dimension */
111   PetscInt         Nc;   /* Field components */
112   PetscReal       *tmpB, *tmpD, *tmpH;
113   PetscInt         p, d, j, k, c;
114   PetscErrorCode   ierr;
115 
116   PetscFunctionBegin;
117   ierr = PetscDualSpaceGetDM(fem->dualSpace, &dm);CHKERRQ(ierr);
118   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
119   ierr = PetscDualSpaceGetDimension(fem->dualSpace, &pdim);CHKERRQ(ierr);
120   ierr = PetscFEGetNumComponents(fem, &Nc);CHKERRQ(ierr);
121   /* Evaluate the prime basis functions at all points */
122   if (B) {ierr = DMGetWorkArray(dm, npoints*pdim*Nc, MPIU_REAL, &tmpB);CHKERRQ(ierr);}
123   if (D) {ierr = DMGetWorkArray(dm, npoints*pdim*Nc*dim, MPIU_REAL, &tmpD);CHKERRQ(ierr);}
124   if (H) {ierr = DMGetWorkArray(dm, npoints*pdim*Nc*dim*dim, MPIU_REAL, &tmpH);CHKERRQ(ierr);}
125   ierr = PetscSpaceEvaluate(fem->basisSpace, npoints, points, B ? tmpB : NULL, D ? tmpD : NULL, H ? tmpH : NULL);CHKERRQ(ierr);
126   /* Translate to the nodal basis */
127   for (p = 0; p < npoints; ++p) {
128     if (B) {
129       /* Multiply by V^{-1} (pdim x pdim) */
130       for (j = 0; j < pdim; ++j) {
131         const PetscInt i = (p*pdim + j)*Nc;
132 
133         for (c = 0; c < Nc; ++c) {
134           B[i+c] = 0.0;
135           for (k = 0; k < pdim; ++k) {
136             B[i+c] += fem->invV[k*pdim+j] * tmpB[(p*pdim + k)*Nc+c];
137           }
138         }
139       }
140     }
141     if (D) {
142       /* Multiply by V^{-1} (pdim x pdim) */
143       for (j = 0; j < pdim; ++j) {
144         for (c = 0; c < Nc; ++c) {
145           for (d = 0; d < dim; ++d) {
146             const PetscInt i = ((p*pdim + j)*Nc + c)*dim + d;
147 
148             D[i] = 0.0;
149             for (k = 0; k < pdim; ++k) {
150               D[i] += fem->invV[k*pdim+j] * tmpD[((p*pdim + k)*Nc + c)*dim + d];
151             }
152           }
153         }
154       }
155     }
156     if (H) {
157       /* Multiply by V^{-1} (pdim x pdim) */
158       for (j = 0; j < pdim; ++j) {
159         for (c = 0; c < Nc; ++c) {
160           for (d = 0; d < dim*dim; ++d) {
161             const PetscInt i = ((p*pdim + j)*Nc + c)*dim*dim + d;
162 
163             H[i] = 0.0;
164             for (k = 0; k < pdim; ++k) {
165               H[i] += fem->invV[k*pdim+j] * tmpH[((p*pdim + k)*Nc + c)*dim*dim + d];
166             }
167           }
168         }
169       }
170     }
171   }
172   if (B) {ierr = DMRestoreWorkArray(dm, npoints*pdim*Nc, MPIU_REAL, &tmpB);CHKERRQ(ierr);}
173   if (D) {ierr = DMRestoreWorkArray(dm, npoints*pdim*Nc*dim, MPIU_REAL, &tmpD);CHKERRQ(ierr);}
174   if (H) {ierr = DMRestoreWorkArray(dm, npoints*pdim*Nc*dim*dim, MPIU_REAL, &tmpH);CHKERRQ(ierr);}
175   PetscFunctionReturn(0);
176 }
177 
178 PetscErrorCode PetscFEIntegrate_Basic(PetscDS ds, PetscInt field, PetscInt Ne, PetscFEGeom *cgeom,
179                                       const PetscScalar coefficients[], PetscDS dsAux, const PetscScalar coefficientsAux[], PetscScalar integral[])
180 {
181   const PetscInt     debug = 0;
182   PetscFE            fe;
183   PetscPointFunc     obj_func;
184   PetscQuadrature    quad;
185   PetscScalar       *u, *u_x, *a, *a_x;
186   const PetscScalar *constants;
187   PetscReal         *x;
188   PetscReal        **B, **D, **BAux = NULL, **DAux = NULL;
189   PetscInt          *uOff, *uOff_x, *aOff = NULL, *aOff_x = NULL, *Nb, *Nc, *NbAux = NULL, *NcAux = NULL;
190   PetscInt           dim, dE, Np, numConstants, Nf, NfAux = 0, totDim, totDimAux = 0, cOffset = 0, cOffsetAux = 0, e;
191   PetscBool          isAffine;
192   const PetscReal   *quadPoints, *quadWeights;
193   PetscInt           qNc, Nq, q;
194   PetscErrorCode     ierr;
195 
196   PetscFunctionBegin;
197   ierr = PetscDSGetObjective(ds, field, &obj_func);CHKERRQ(ierr);
198   if (!obj_func) PetscFunctionReturn(0);
199   ierr = PetscDSGetDiscretization(ds, field, (PetscObject *) &fe);CHKERRQ(ierr);
200   ierr = PetscFEGetSpatialDimension(fe, &dim);CHKERRQ(ierr);
201   ierr = PetscFEGetQuadrature(fe, &quad);CHKERRQ(ierr);
202   ierr = PetscDSGetNumFields(ds, &Nf);CHKERRQ(ierr);
203   ierr = PetscDSGetTotalDimension(ds, &totDim);CHKERRQ(ierr);
204   ierr = PetscDSGetDimensions(ds, &Nb);CHKERRQ(ierr);
205   ierr = PetscDSGetComponents(ds, &Nc);CHKERRQ(ierr);
206   ierr = PetscDSGetComponentOffsets(ds, &uOff);CHKERRQ(ierr);
207   ierr = PetscDSGetComponentDerivativeOffsets(ds, &uOff_x);CHKERRQ(ierr);
208   ierr = PetscDSGetEvaluationArrays(ds, &u, NULL, &u_x);CHKERRQ(ierr);
209   ierr = PetscDSGetWorkspace(ds, &x, NULL, NULL, NULL, NULL);CHKERRQ(ierr);
210   ierr = PetscDSGetTabulation(ds, &B, &D);CHKERRQ(ierr);
211   ierr = PetscDSGetConstants(ds, &numConstants, &constants);CHKERRQ(ierr);
212   if (dsAux) {
213     ierr = PetscDSGetNumFields(dsAux, &NfAux);CHKERRQ(ierr);
214     ierr = PetscDSGetTotalDimension(dsAux, &totDimAux);CHKERRQ(ierr);
215     ierr = PetscDSGetDimensions(dsAux, &NbAux);CHKERRQ(ierr);
216     ierr = PetscDSGetComponents(dsAux, &NcAux);CHKERRQ(ierr);
217     ierr = PetscDSGetComponentOffsets(dsAux, &aOff);CHKERRQ(ierr);
218     ierr = PetscDSGetComponentDerivativeOffsets(dsAux, &aOff_x);CHKERRQ(ierr);
219     ierr = PetscDSGetEvaluationArrays(dsAux, &a, NULL, &a_x);CHKERRQ(ierr);
220     ierr = PetscDSGetTabulation(dsAux, &BAux, &DAux);CHKERRQ(ierr);
221   }
222   ierr = PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights);CHKERRQ(ierr);
223   if (qNc != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Only supports scalar quadrature, not %D components\n", qNc);
224   Np = cgeom->numPoints;
225   dE = cgeom->dimEmbed;
226   isAffine = cgeom->isAffine;
227   for (e = 0; e < Ne; ++e) {
228     PetscFEGeom fegeom;
229 
230     if (isAffine) {
231       fegeom.v    = x;
232       fegeom.xi   = cgeom->xi;
233       fegeom.J    = &cgeom->J[e*dE*dE];
234       fegeom.invJ = &cgeom->invJ[e*dE*dE];
235       fegeom.detJ = &cgeom->detJ[e];
236     }
237     for (q = 0; q < Nq; ++q) {
238       PetscScalar integrand;
239       PetscReal   w;
240 
241       if (isAffine) {
242         CoordinatesRefToReal(dE, dim, fegeom.xi, &cgeom->v[e*dE], fegeom.J, &quadPoints[q*dim], x);
243       } else {
244         fegeom.v    = &cgeom->v[(e*Np+q)*dE];
245         fegeom.J    = &cgeom->J[(e*Np+q)*dE*dE];
246         fegeom.invJ = &cgeom->invJ[(e*Np+q)*dE*dE];
247         fegeom.detJ = &cgeom->detJ[e*Np+q];
248       }
249       w = fegeom.detJ[0]*quadWeights[q];
250       if (debug > 1 && q < Np) {
251         ierr = PetscPrintf(PETSC_COMM_SELF, "  detJ: %g\n", fegeom.detJ[0]);CHKERRQ(ierr);
252 #if !defined(PETSC_USE_COMPLEX)
253         ierr = DMPrintCellMatrix(e, "invJ", dim, dim, fegeom.invJ);CHKERRQ(ierr);
254 #endif
255       }
256       if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "  quad point %d\n", q);CHKERRQ(ierr);}
257       ierr = PetscFEEvaluateFieldJets_Internal(ds, dim, Nf, Nb, Nc, q, B, D, &fegeom, &coefficients[cOffset], NULL, u, u_x, NULL);CHKERRQ(ierr);
258       if (dsAux) {ierr = PetscFEEvaluateFieldJets_Internal(dsAux, dim, NfAux, NbAux, NcAux, q, BAux, DAux, &fegeom, &coefficientsAux[cOffsetAux], NULL, a, a_x, NULL);CHKERRQ(ierr);}
259       obj_func(dim, Nf, NfAux, uOff, uOff_x, u, NULL, u_x, aOff, aOff_x, a, NULL, a_x, 0.0, fegeom.v, numConstants, constants, &integrand);
260       integrand *= w;
261       integral[e*Nf+field] += integrand;
262       if (debug > 1) {ierr = PetscPrintf(PETSC_COMM_SELF, "    int: %g %g\n", (double) PetscRealPart(integrand), (double) PetscRealPart(integral[field]));CHKERRQ(ierr);}
263     }
264     cOffset    += totDim;
265     cOffsetAux += totDimAux;
266   }
267   PetscFunctionReturn(0);
268 }
269 
270 PetscErrorCode PetscFEIntegrateBd_Basic(PetscDS ds, PetscInt field,
271                                         PetscBdPointFunc obj_func,
272                                         PetscInt Ne, PetscFEGeom *fgeom, const PetscScalar coefficients[], PetscDS dsAux, const PetscScalar coefficientsAux[], PetscScalar integral[])
273 {
274   const PetscInt     debug = 0;
275   PetscFE            fe;
276   PetscQuadrature    quad;
277   PetscScalar       *u, *u_x, *a, *a_x, *basisReal, *basisDerReal;
278   const PetscScalar *constants;
279   PetscReal         *x;
280   PetscReal        **B, **D, **BAux = NULL, **DAux = NULL;
281   PetscInt          *uOff, *uOff_x, *aOff = NULL, *aOff_x = NULL, *Nb, *Nc, *NbAux = NULL, *NcAux = NULL;
282   PetscBool          isAffine, auxOnBd;
283   const PetscReal   *quadPoints, *quadWeights;
284   PetscInt           qNc, Nq, q, Np, dE;
285   PetscInt           dim, dimAux, numConstants, Nf, NfAux = 0, totDim, totDimAux = 0, cOffset = 0, cOffsetAux = 0, e;
286   PetscErrorCode     ierr;
287 
288   PetscFunctionBegin;
289   if (!obj_func) PetscFunctionReturn(0);
290   ierr = PetscDSGetDiscretization(ds, field, (PetscObject *) &fe);CHKERRQ(ierr);
291   ierr = PetscFEGetSpatialDimension(fe, &dim);CHKERRQ(ierr);
292   ierr = PetscFEGetFaceQuadrature(fe, &quad);CHKERRQ(ierr);
293   ierr = PetscDSGetNumFields(ds, &Nf);CHKERRQ(ierr);
294   ierr = PetscDSGetTotalDimension(ds, &totDim);CHKERRQ(ierr);
295   ierr = PetscDSGetDimensions(ds, &Nb);CHKERRQ(ierr);
296   ierr = PetscDSGetComponents(ds, &Nc);CHKERRQ(ierr);
297   ierr = PetscDSGetComponentOffsets(ds, &uOff);CHKERRQ(ierr);
298   ierr = PetscDSGetComponentDerivativeOffsets(ds, &uOff_x);CHKERRQ(ierr);
299   ierr = PetscDSGetEvaluationArrays(ds, &u, NULL, &u_x);CHKERRQ(ierr);
300   ierr = PetscDSGetWorkspace(ds, &x, &basisReal, &basisDerReal, NULL, NULL);CHKERRQ(ierr);
301   ierr = PetscDSGetFaceTabulation(ds, &B, &D);CHKERRQ(ierr);
302   ierr = PetscDSGetConstants(ds, &numConstants, &constants);CHKERRQ(ierr);
303   if (dsAux) {
304     ierr = PetscDSGetSpatialDimension(dsAux, &dimAux);CHKERRQ(ierr);
305     ierr = PetscDSGetNumFields(dsAux, &NfAux);CHKERRQ(ierr);
306     ierr = PetscDSGetTotalDimension(dsAux, &totDimAux);CHKERRQ(ierr);
307     ierr = PetscDSGetDimensions(dsAux, &NbAux);CHKERRQ(ierr);
308     ierr = PetscDSGetComponents(dsAux, &NcAux);CHKERRQ(ierr);
309     ierr = PetscDSGetComponentOffsets(dsAux, &aOff);CHKERRQ(ierr);
310     ierr = PetscDSGetComponentDerivativeOffsets(dsAux, &aOff_x);CHKERRQ(ierr);
311     ierr = PetscDSGetEvaluationArrays(dsAux, &a, NULL, &a_x);CHKERRQ(ierr);
312     auxOnBd = dimAux < dim ? PETSC_TRUE : PETSC_FALSE;
313     if (auxOnBd) {ierr = PetscDSGetTabulation(dsAux, &BAux, &DAux);CHKERRQ(ierr);}
314     else         {ierr = PetscDSGetFaceTabulation(dsAux, &BAux, &DAux);CHKERRQ(ierr);}
315   }
316   ierr = PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights);CHKERRQ(ierr);
317   if (qNc != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Only supports scalar quadrature, not %D components\n", qNc);
318   Np = fgeom->numPoints;
319   dE = fgeom->dimEmbed;
320   isAffine = fgeom->isAffine;
321   for (e = 0; e < Ne; ++e) {
322     PetscFEGeom    fegeom;
323     const PetscInt face = fgeom->face[e][0]; /* Local face number in cell */
324 
325     if (isAffine) {
326       fegeom.v    = x;
327       fegeom.xi   = fgeom->xi;
328       fegeom.J    = &fgeom->J[e*dE*dE];
329       fegeom.invJ = &fgeom->suppInvJ[0][e*dE*dE];
330       fegeom.detJ = &fgeom->detJ[e];
331       fegeom.n    = &fgeom->n[e*dE];
332     }
333     for (q = 0; q < Nq; ++q) {
334       PetscScalar integrand;
335       PetscReal   w;
336 
337       if (isAffine) {
338         CoordinatesRefToReal(dE, dim-1, fegeom.xi, &fgeom->v[e*dE], fegeom.J, &quadPoints[q*(dim-1)], x);
339       } else {
340         fegeom.v    = &fegeom.v[(e*Np+q)*dE];
341         fegeom.invJ = &fgeom->suppInvJ[0][(e*Np+q)*dE*dE];
342         fegeom.detJ = &fgeom->detJ[e*Np+q];
343         fegeom.n    = &fgeom->n[(e*Np+q)*dE];
344       }
345       w = fegeom.detJ[0]*quadWeights[q];
346       if (debug > 1 && q < Np) {
347         ierr = PetscPrintf(PETSC_COMM_SELF, "  detJ: %g\n", fegeom.detJ[0]);CHKERRQ(ierr);
348 #ifndef PETSC_USE_COMPLEX
349         ierr = DMPrintCellMatrix(e, "invJ", dim, dim, fegeom.invJ);CHKERRQ(ierr);
350 #endif
351       }
352       if (debug > 1) {ierr = PetscPrintf(PETSC_COMM_SELF, "  quad point %d\n", q);CHKERRQ(ierr);}
353       ierr = PetscFEEvaluateFieldJets_Internal(ds, dim, Nf, Nb, Nc, face*Nq+q, B, D, &fegeom, &coefficients[cOffset], NULL, u, u_x, NULL);CHKERRQ(ierr);
354       if (dsAux) {ierr = PetscFEEvaluateFieldJets_Internal(dsAux, dimAux, NfAux, NbAux, NcAux, face*Nq+q, BAux, DAux, &fegeom, &coefficientsAux[cOffsetAux], NULL, a, a_x, NULL);CHKERRQ(ierr);}
355       obj_func(dim, Nf, NfAux, uOff, uOff_x, u, NULL, u_x, aOff, aOff_x, a, NULL, a_x, 0.0, fegeom.v, fegeom.n, numConstants, constants, &integrand);
356       integrand *= w;
357       integral[e*Nf+field] += integrand;
358       if (debug > 1) {ierr = PetscPrintf(PETSC_COMM_SELF, "    int: %g %g\n", (double) PetscRealPart(integrand), (double) PetscRealPart(integral[e*Nf+field]));CHKERRQ(ierr);}
359     }
360     cOffset    += totDim;
361     cOffsetAux += totDimAux;
362   }
363   PetscFunctionReturn(0);
364 }
365 
366 PetscErrorCode PetscFEIntegrateResidual_Basic(PetscDS ds, PetscInt field, PetscInt Ne, PetscFEGeom *cgeom,
367                                               const PetscScalar coefficients[], const PetscScalar coefficients_t[], PetscDS dsAux, const PetscScalar coefficientsAux[], PetscReal t, PetscScalar elemVec[])
368 {
369   const PetscInt     debug = 0;
370   PetscFE            fe;
371   PetscPointFunc     f0_func;
372   PetscPointFunc     f1_func;
373   PetscQuadrature    quad;
374   PetscScalar       *f0, *f1, *u, *u_t = NULL, *u_x, *a, *a_x, *basisReal, *basisDerReal;
375   const PetscScalar *constants;
376   PetscReal         *x;
377   PetscReal        **B, **D, **BAux = NULL, **DAux = NULL, *BI, *DI;
378   PetscInt          *uOff, *uOff_x, *aOff = NULL, *aOff_x = NULL, *Nb, *Nc, *NbAux = NULL, *NcAux = NULL;
379   PetscInt           dim, numConstants, Nf, NfAux = 0, totDim, totDimAux = 0, cOffset = 0, cOffsetAux = 0, fOffset, e, NbI, NcI;
380   PetscBool          isAffine;
381   const PetscReal   *quadPoints, *quadWeights;
382   PetscInt           qNc, Nq, q, Np, dE;
383   PetscErrorCode     ierr;
384 
385   PetscFunctionBegin;
386   ierr = PetscDSGetDiscretization(ds, field, (PetscObject *) &fe);CHKERRQ(ierr);
387   ierr = PetscFEGetSpatialDimension(fe, &dim);CHKERRQ(ierr);
388   ierr = PetscFEGetQuadrature(fe, &quad);CHKERRQ(ierr);
389   ierr = PetscDSGetNumFields(ds, &Nf);CHKERRQ(ierr);
390   ierr = PetscDSGetTotalDimension(ds, &totDim);CHKERRQ(ierr);
391   ierr = PetscDSGetDimensions(ds, &Nb);CHKERRQ(ierr);
392   ierr = PetscDSGetComponents(ds, &Nc);CHKERRQ(ierr);
393   ierr = PetscDSGetComponentOffsets(ds, &uOff);CHKERRQ(ierr);
394   ierr = PetscDSGetComponentDerivativeOffsets(ds, &uOff_x);CHKERRQ(ierr);
395   ierr = PetscDSGetFieldOffset(ds, field, &fOffset);CHKERRQ(ierr);
396   ierr = PetscDSGetResidual(ds, field, &f0_func, &f1_func);CHKERRQ(ierr);
397   ierr = PetscDSGetEvaluationArrays(ds, &u, coefficients_t ? &u_t : NULL, &u_x);CHKERRQ(ierr);
398   ierr = PetscDSGetWorkspace(ds, &x, &basisReal, &basisDerReal, NULL, NULL);CHKERRQ(ierr);
399   ierr = PetscDSGetWeakFormArrays(ds, &f0, &f1, NULL, NULL, NULL, NULL);CHKERRQ(ierr);
400   if (!f0_func && !f1_func) PetscFunctionReturn(0);
401   ierr = PetscDSGetTabulation(ds, &B, &D);CHKERRQ(ierr);
402   ierr = PetscDSGetConstants(ds, &numConstants, &constants);CHKERRQ(ierr);
403   if (dsAux) {
404     ierr = PetscDSGetNumFields(dsAux, &NfAux);CHKERRQ(ierr);
405     ierr = PetscDSGetTotalDimension(dsAux, &totDimAux);CHKERRQ(ierr);
406     ierr = PetscDSGetDimensions(dsAux, &NbAux);CHKERRQ(ierr);
407     ierr = PetscDSGetComponents(dsAux, &NcAux);CHKERRQ(ierr);
408     ierr = PetscDSGetComponentOffsets(dsAux, &aOff);CHKERRQ(ierr);
409     ierr = PetscDSGetComponentDerivativeOffsets(dsAux, &aOff_x);CHKERRQ(ierr);
410     ierr = PetscDSGetEvaluationArrays(dsAux, &a, NULL, &a_x);CHKERRQ(ierr);
411     ierr = PetscDSGetTabulation(dsAux, &BAux, &DAux);CHKERRQ(ierr);
412   }
413   NbI = Nb[field];
414   NcI = Nc[field];
415   BI  = B[field];
416   DI  = D[field];
417   ierr = PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights);CHKERRQ(ierr);
418   if (qNc != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Only supports scalar quadrature, not %D components\n", qNc);
419   Np = cgeom->numPoints;
420   dE = cgeom->dimEmbed;
421   isAffine = cgeom->isAffine;
422   for (e = 0; e < Ne; ++e) {
423     PetscFEGeom fegeom;
424 
425     if (isAffine) {
426       fegeom.v    = x;
427       fegeom.xi   = cgeom->xi;
428       fegeom.J    = &cgeom->J[e*dE*dE];
429       fegeom.invJ = &cgeom->invJ[e*dE*dE];
430       fegeom.detJ = &cgeom->detJ[e];
431     }
432     ierr = PetscMemzero(f0, Nq*NcI* sizeof(PetscScalar));CHKERRQ(ierr);
433     ierr = PetscMemzero(f1, Nq*NcI*dim * sizeof(PetscScalar));CHKERRQ(ierr);
434     for (q = 0; q < Nq; ++q) {
435       PetscReal w;
436       PetscInt  c, d;
437 
438       if (isAffine) {
439         CoordinatesRefToReal(dE, dim, fegeom.xi, &cgeom->v[e*dE], fegeom.J, &quadPoints[q*dim], x);
440       } else {
441         fegeom.v    = &cgeom->v[(e*Np+q)*dE];
442         fegeom.J    = &cgeom->J[(e*Np+q)*dE*dE];
443         fegeom.invJ = &cgeom->invJ[(e*Np+q)*dE*dE];
444         fegeom.detJ = &cgeom->detJ[e*Np+q];
445       }
446       w = fegeom.detJ[0]*quadWeights[q];
447       if (debug > 1 && q < Np) {
448         ierr = PetscPrintf(PETSC_COMM_SELF, "  detJ: %g\n", fegeom.detJ[0]);CHKERRQ(ierr);
449 #if !defined(PETSC_USE_COMPLEX)
450         ierr = DMPrintCellMatrix(e, "invJ", dim, dim, fegeom.invJ);CHKERRQ(ierr);
451 #endif
452       }
453       if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "  quad point %d\n", q);CHKERRQ(ierr);}
454       ierr = PetscFEEvaluateFieldJets_Internal(ds, dim, Nf, Nb, Nc, q, B, D, &fegeom, &coefficients[cOffset], &coefficients_t[cOffset], u, u_x, u_t);CHKERRQ(ierr);
455       if (dsAux) {ierr = PetscFEEvaluateFieldJets_Internal(dsAux, dim, NfAux, NbAux, NcAux, q, BAux, DAux, &fegeom, &coefficientsAux[cOffsetAux], NULL, a, a_x, NULL);CHKERRQ(ierr);}
456       if (f0_func) {
457         f0_func(dim, Nf, NfAux, uOff, uOff_x, u, u_t, u_x, aOff, aOff_x, a, NULL, a_x, t, fegeom.v, numConstants, constants, &f0[q*NcI]);
458         for (c = 0; c < NcI; ++c) f0[q*NcI+c] *= w;
459       }
460       if (f1_func) {
461         f1_func(dim, Nf, NfAux, uOff, uOff_x, u, u_t, u_x, aOff, aOff_x, a, NULL, a_x, t, fegeom.v, numConstants, constants, &f1[q*NcI*dim]);
462         for (c = 0; c < NcI; ++c) for (d = 0; d < dim; ++d) f1[(q*NcI+c)*dim+d] *= w;
463       }
464     }
465     ierr = PetscFEUpdateElementVec_Internal(fe, dim, Nq, NbI, NcI, BI, DI, basisReal, basisDerReal, &fegeom, f0, f1, &elemVec[cOffset+fOffset]);CHKERRQ(ierr);
466     cOffset    += totDim;
467     cOffsetAux += totDimAux;
468   }
469   PetscFunctionReturn(0);
470 }
471 
472 PetscErrorCode PetscFEIntegrateBdResidual_Basic(PetscDS ds, PetscInt field, PetscInt Ne, PetscFEGeom *fgeom,
473                                                 const PetscScalar coefficients[], const PetscScalar coefficients_t[], PetscDS dsAux, const PetscScalar coefficientsAux[], PetscReal t, PetscScalar elemVec[])
474 {
475   const PetscInt     debug = 0;
476   PetscFE            fe;
477   PetscBdPointFunc   f0_func;
478   PetscBdPointFunc   f1_func;
479   PetscQuadrature    quad;
480   PetscScalar       *f0, *f1, *u, *u_t = NULL, *u_x, *a, *a_x, *basisReal, *basisDerReal;
481   const PetscScalar *constants;
482   PetscReal         *x;
483   PetscReal        **B, **D, **BAux = NULL, **DAux = NULL, *BI, *DI;
484   PetscInt          *uOff, *uOff_x, *aOff = NULL, *aOff_x = NULL, *Nb, *Nc, *NbAux = NULL, *NcAux = NULL;
485   PetscInt           dim, dimAux, numConstants, Nf, NfAux = 0, totDim, totDimAux = 0, cOffset = 0, cOffsetAux = 0, fOffset, e, NbI, NcI;
486   PetscBool          isAffine, auxOnBd = PETSC_FALSE;
487   const PetscReal   *quadPoints, *quadWeights;
488   PetscInt           qNc, Nq, q, Np, dE;
489   PetscErrorCode     ierr;
490 
491   PetscFunctionBegin;
492   ierr = PetscDSGetDiscretization(ds, field, (PetscObject *) &fe);CHKERRQ(ierr);
493   ierr = PetscFEGetSpatialDimension(fe, &dim);CHKERRQ(ierr);
494   ierr = PetscFEGetFaceQuadrature(fe, &quad);CHKERRQ(ierr);
495   ierr = PetscDSGetNumFields(ds, &Nf);CHKERRQ(ierr);
496   ierr = PetscDSGetTotalDimension(ds, &totDim);CHKERRQ(ierr);
497   ierr = PetscDSGetDimensions(ds, &Nb);CHKERRQ(ierr);
498   ierr = PetscDSGetComponents(ds, &Nc);CHKERRQ(ierr);
499   ierr = PetscDSGetComponentOffsets(ds, &uOff);CHKERRQ(ierr);
500   ierr = PetscDSGetComponentDerivativeOffsets(ds, &uOff_x);CHKERRQ(ierr);
501   ierr = PetscDSGetFieldOffset(ds, field, &fOffset);CHKERRQ(ierr);
502   ierr = PetscDSGetBdResidual(ds, field, &f0_func, &f1_func);CHKERRQ(ierr);
503   if (!f0_func && !f1_func) PetscFunctionReturn(0);
504   ierr = PetscDSGetEvaluationArrays(ds, &u, coefficients_t ? &u_t : NULL, &u_x);CHKERRQ(ierr);
505   ierr = PetscDSGetWorkspace(ds, &x, &basisReal, &basisDerReal, NULL, NULL);CHKERRQ(ierr);
506   ierr = PetscDSGetWeakFormArrays(ds, &f0, &f1, NULL, NULL, NULL, NULL);CHKERRQ(ierr);
507   ierr = PetscDSGetFaceTabulation(ds, &B, &D);CHKERRQ(ierr);
508   ierr = PetscDSGetConstants(ds, &numConstants, &constants);CHKERRQ(ierr);
509   if (dsAux) {
510     ierr = PetscDSGetSpatialDimension(dsAux, &dimAux);CHKERRQ(ierr);
511     ierr = PetscDSGetNumFields(dsAux, &NfAux);CHKERRQ(ierr);
512     ierr = PetscDSGetTotalDimension(dsAux, &totDimAux);CHKERRQ(ierr);
513     ierr = PetscDSGetDimensions(dsAux, &NbAux);CHKERRQ(ierr);
514     ierr = PetscDSGetComponents(dsAux, &NcAux);CHKERRQ(ierr);
515     ierr = PetscDSGetComponentOffsets(dsAux, &aOff);CHKERRQ(ierr);
516     ierr = PetscDSGetComponentDerivativeOffsets(dsAux, &aOff_x);CHKERRQ(ierr);
517     ierr = PetscDSGetEvaluationArrays(dsAux, &a, NULL, &a_x);CHKERRQ(ierr);
518     auxOnBd = dimAux < dim ? PETSC_TRUE : PETSC_FALSE;
519     if (auxOnBd) {ierr = PetscDSGetTabulation(dsAux, &BAux, &DAux);CHKERRQ(ierr);}
520     else         {ierr = PetscDSGetFaceTabulation(dsAux, &BAux, &DAux);CHKERRQ(ierr);}
521   }
522   NbI = Nb[field];
523   NcI = Nc[field];
524   BI  = B[field];
525   DI  = D[field];
526   ierr = PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights);CHKERRQ(ierr);
527   if (qNc != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Only supports scalar quadrature, not %D components\n", qNc);
528   Np = fgeom->numPoints;
529   dE = fgeom->dimEmbed;
530   isAffine = fgeom->isAffine;
531   for (e = 0; e < Ne; ++e) {
532     PetscFEGeom    fegeom;
533     const PetscInt face = fgeom->face[e][0];
534 
535     if (isAffine) {
536       fegeom.v    = x;
537       fegeom.xi   = fgeom->xi;
538       fegeom.J    = &fgeom->J[e*dE*dE];
539       fegeom.invJ = &fgeom->suppInvJ[0][e*dE*dE];
540       fegeom.detJ = &fgeom->detJ[e];
541       fegeom.n    = &fgeom->n[e*dE];
542     }
543     ierr = PetscMemzero(f0, Nq*NcI* sizeof(PetscScalar));CHKERRQ(ierr);
544     ierr = PetscMemzero(f1, Nq*NcI*dim * sizeof(PetscScalar));CHKERRQ(ierr);
545     for (q = 0; q < Nq; ++q) {
546       PetscReal w;
547       PetscInt  c, d;
548 
549       if (isAffine) {
550         CoordinatesRefToReal(dE, dim-1, fegeom.xi, &fgeom->v[e*dE], fegeom.J, &quadPoints[q*(dim-1)], x);
551       } else {
552         fegeom.v    = &fegeom.v[(e*Np+q)*dE];
553         fegeom.invJ = &fgeom->suppInvJ[0][(e*Np+q)*dE*dE];
554         fegeom.detJ = &fgeom->detJ[e*Np+q];
555         fegeom.n    = &fgeom->n[(e*Np+q)*dE];
556       }
557       w = fegeom.detJ[0]*quadWeights[q];
558       if (debug > 1 && q < Np) {
559         ierr = PetscPrintf(PETSC_COMM_SELF, "  detJ: %g\n", fegeom.detJ[0]);CHKERRQ(ierr);
560 #if !defined(PETSC_USE_COMPLEX)
561         ierr = DMPrintCellMatrix(e, "invJ", dim, dim, fegeom.invJ);CHKERRQ(ierr);
562 #endif
563       }
564       if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "  quad point %d\n", q);CHKERRQ(ierr);}
565       ierr = PetscFEEvaluateFieldJets_Internal(ds, dim, Nf, Nb, Nc, face*Nq+q, B, D, &fegeom, &coefficients[cOffset], &coefficients_t[cOffset], u, u_x, u_t);CHKERRQ(ierr);
566       if (dsAux) {ierr = PetscFEEvaluateFieldJets_Internal(dsAux, dimAux, NfAux, NbAux, NcAux, auxOnBd ? q : face*Nq+q, BAux, DAux, &fegeom, &coefficientsAux[cOffsetAux], NULL, a, a_x, NULL);CHKERRQ(ierr);}
567       if (f0_func) {
568         f0_func(dim, Nf, NfAux, uOff, uOff_x, u, u_t, u_x, aOff, aOff_x, a, NULL, a_x, t, fegeom.v, fegeom.n, numConstants, constants, &f0[q*NcI]);
569         for (c = 0; c < NcI; ++c) f0[q*NcI+c] *= w;
570       }
571       if (f1_func) {
572         f1_func(dim, Nf, NfAux, uOff, uOff_x, u, u_t, u_x, aOff, aOff_x, a, NULL, a_x, t, fegeom.v, fegeom.n, numConstants, constants, &f1[q*NcI*dim]);
573         for (c = 0; c < NcI; ++c) for (d = 0; d < dim; ++d) f1[(q*NcI+c)*dim+d] *= w;
574       }
575     }
576     ierr = PetscFEUpdateElementVec_Internal(fe, dim, Nq, NbI, NcI, &BI[face*Nq*NbI*NcI], &DI[face*Nq*NbI*NcI*dim], basisReal, basisDerReal, &fegeom, f0, f1, &elemVec[cOffset+fOffset]);CHKERRQ(ierr);
577     cOffset    += totDim;
578     cOffsetAux += totDimAux;
579   }
580   PetscFunctionReturn(0);
581 }
582 
583 PetscErrorCode PetscFEIntegrateJacobian_Basic(PetscDS ds, PetscFEJacobianType jtype, PetscInt fieldI, PetscInt fieldJ, PetscInt Ne, PetscFEGeom *cgeom,
584                                               const PetscScalar coefficients[], const PetscScalar coefficients_t[], PetscDS dsAux, const PetscScalar coefficientsAux[], PetscReal t, PetscReal u_tshift, PetscScalar elemMat[])
585 {
586   const PetscInt     debug      = 0;
587   PetscFE            feI, feJ;
588   PetscPointJac      g0_func, g1_func, g2_func, g3_func;
589   PetscInt           cOffset    = 0; /* Offset into coefficients[] for element e */
590   PetscInt           cOffsetAux = 0; /* Offset into coefficientsAux[] for element e */
591   PetscInt           eOffset    = 0; /* Offset into elemMat[] for element e */
592   PetscInt           offsetI    = 0; /* Offset into an element vector for fieldI */
593   PetscInt           offsetJ    = 0; /* Offset into an element vector for fieldJ */
594   PetscQuadrature    quad;
595   PetscScalar       *g0, *g1, *g2, *g3, *u, *u_t = NULL, *u_x, *a, *a_x, *basisReal, *basisDerReal, *testReal, *testDerReal;
596   const PetscScalar *constants;
597   PetscReal         *x;
598   PetscReal        **B, **D, **BAux = NULL, **DAux = NULL, *BI, *DI, *BJ, *DJ;
599   PetscInt          *uOff, *uOff_x, *aOff = NULL, *aOff_x = NULL, *Nb, *Nc, *NbAux = NULL, *NcAux = NULL;
600   PetscInt           NbI = 0, NcI = 0, NbJ = 0, NcJ = 0;
601   PetscInt           dim, numConstants, Nf, NfAux = 0, totDim, totDimAux = 0, e;
602   PetscInt           dE, Np;
603   PetscBool          isAffine;
604   const PetscReal   *quadPoints, *quadWeights;
605   PetscInt           qNc, Nq, q;
606   PetscErrorCode     ierr;
607 
608   PetscFunctionBegin;
609   ierr = PetscDSGetDiscretization(ds, fieldI, (PetscObject *) &feI);CHKERRQ(ierr);
610   ierr = PetscDSGetDiscretization(ds, fieldJ, (PetscObject *) &feJ);CHKERRQ(ierr);
611   ierr = PetscFEGetSpatialDimension(feI, &dim);CHKERRQ(ierr);
612   ierr = PetscFEGetQuadrature(feI, &quad);CHKERRQ(ierr);
613   ierr = PetscDSGetNumFields(ds, &Nf);CHKERRQ(ierr);
614   ierr = PetscDSGetTotalDimension(ds, &totDim);CHKERRQ(ierr);
615   ierr = PetscDSGetDimensions(ds, &Nb);CHKERRQ(ierr);
616   ierr = PetscDSGetComponents(ds, &Nc);CHKERRQ(ierr);
617   ierr = PetscDSGetComponentOffsets(ds, &uOff);CHKERRQ(ierr);
618   ierr = PetscDSGetComponentDerivativeOffsets(ds, &uOff_x);CHKERRQ(ierr);
619   switch(jtype) {
620   case PETSCFE_JACOBIAN_DYN: ierr = PetscDSGetDynamicJacobian(ds, fieldI, fieldJ, &g0_func, &g1_func, &g2_func, &g3_func);CHKERRQ(ierr);break;
621   case PETSCFE_JACOBIAN_PRE: ierr = PetscDSGetJacobianPreconditioner(ds, fieldI, fieldJ, &g0_func, &g1_func, &g2_func, &g3_func);CHKERRQ(ierr);break;
622   case PETSCFE_JACOBIAN:     ierr = PetscDSGetJacobian(ds, fieldI, fieldJ, &g0_func, &g1_func, &g2_func, &g3_func);CHKERRQ(ierr);break;
623   }
624   if (!g0_func && !g1_func && !g2_func && !g3_func) PetscFunctionReturn(0);
625   ierr = PetscDSGetEvaluationArrays(ds, &u, coefficients_t ? &u_t : NULL, &u_x);CHKERRQ(ierr);
626   ierr = PetscDSGetWorkspace(ds, &x, &basisReal, &basisDerReal, &testReal, &testDerReal);CHKERRQ(ierr);
627   ierr = PetscDSGetWeakFormArrays(ds, NULL, NULL, &g0, &g1, &g2, &g3);CHKERRQ(ierr);
628   ierr = PetscDSGetTabulation(ds, &B, &D);CHKERRQ(ierr);
629   ierr = PetscDSGetFieldOffset(ds, fieldI, &offsetI);CHKERRQ(ierr);
630   ierr = PetscDSGetFieldOffset(ds, fieldJ, &offsetJ);CHKERRQ(ierr);
631   ierr = PetscDSGetConstants(ds, &numConstants, &constants);CHKERRQ(ierr);
632   if (dsAux) {
633     ierr = PetscDSGetNumFields(dsAux, &NfAux);CHKERRQ(ierr);
634     ierr = PetscDSGetTotalDimension(dsAux, &totDimAux);CHKERRQ(ierr);
635     ierr = PetscDSGetDimensions(dsAux, &NbAux);CHKERRQ(ierr);
636     ierr = PetscDSGetComponents(dsAux, &NcAux);CHKERRQ(ierr);
637     ierr = PetscDSGetComponentOffsets(dsAux, &aOff);CHKERRQ(ierr);
638     ierr = PetscDSGetComponentDerivativeOffsets(dsAux, &aOff_x);CHKERRQ(ierr);
639     ierr = PetscDSGetEvaluationArrays(dsAux, &a, NULL, &a_x);CHKERRQ(ierr);
640     ierr = PetscDSGetTabulation(dsAux, &BAux, &DAux);CHKERRQ(ierr);
641   }
642   NbI = Nb[fieldI], NbJ = Nb[fieldJ];
643   NcI = Nc[fieldI], NcJ = Nc[fieldJ];
644   BI  = B[fieldI],  BJ  = B[fieldJ];
645   DI  = D[fieldI],  DJ  = D[fieldJ];
646   /* Initialize here in case the function is not defined */
647   ierr = PetscMemzero(g0, NcI*NcJ * sizeof(PetscScalar));CHKERRQ(ierr);
648   ierr = PetscMemzero(g1, NcI*NcJ*dim * sizeof(PetscScalar));CHKERRQ(ierr);
649   ierr = PetscMemzero(g2, NcI*NcJ*dim * sizeof(PetscScalar));CHKERRQ(ierr);
650   ierr = PetscMemzero(g3, NcI*NcJ*dim*dim * sizeof(PetscScalar));CHKERRQ(ierr);
651   ierr = PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights);CHKERRQ(ierr);
652   if (qNc != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Only supports scalar quadrature, not %D components\n", qNc);
653   Np = cgeom->numPoints;
654   dE = cgeom->dimEmbed;
655   isAffine = cgeom->isAffine;
656   for (e = 0; e < Ne; ++e) {
657     PetscFEGeom fegeom;
658 
659     if (isAffine) {
660       fegeom.v    = x;
661       fegeom.xi   = cgeom->xi;
662       fegeom.J    = &cgeom->J[e*dE*dE];
663       fegeom.invJ = &cgeom->invJ[e*dE*dE];
664       fegeom.detJ = &cgeom->detJ[e];
665     }
666     for (q = 0; q < Nq; ++q) {
667       const PetscReal *BIq = &BI[q*NbI*NcI],     *BJq = &BJ[q*NbJ*NcJ];
668       const PetscReal *DIq = &DI[q*NbI*NcI*dim], *DJq = &DJ[q*NbJ*NcJ*dim];
669       PetscReal        w;
670       PetscInt         c;
671 
672       if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "  quad point %d\n", q);CHKERRQ(ierr);}
673       if (isAffine) {
674         CoordinatesRefToReal(dE, dim, fegeom.xi, &cgeom->v[e*dE], fegeom.J, &quadPoints[q*dim], x);
675       } else {
676         fegeom.v    = &cgeom->v[(e*Np+q)*dE];
677         fegeom.J    = &cgeom->J[(e*Np+q)*dE*dE];
678         fegeom.invJ = &cgeom->invJ[(e*Np+q)*dE*dE];
679         fegeom.detJ = &cgeom->detJ[e*Np+q];
680       }
681       w = fegeom.detJ[0]*quadWeights[q];
682       if (coefficients) {ierr = PetscFEEvaluateFieldJets_Internal(ds, dim, Nf, Nb, Nc, q, B, D, &fegeom, &coefficients[cOffset], &coefficients_t[cOffset], u, u_x, u_t);CHKERRQ(ierr);}
683       if (dsAux)      {ierr = PetscFEEvaluateFieldJets_Internal(dsAux, dim, NfAux, NbAux, NcAux, q, BAux, DAux, &fegeom, &coefficientsAux[cOffsetAux], NULL, a, a_x, NULL);CHKERRQ(ierr);}
684       if (g0_func) {
685         ierr = PetscMemzero(g0, NcI*NcJ * sizeof(PetscScalar));CHKERRQ(ierr);
686         g0_func(dim, Nf, NfAux, uOff, uOff_x, u, u_t, u_x, aOff, aOff_x, a, NULL, a_x, t, u_tshift, fegeom.v, numConstants, constants, g0);
687         for (c = 0; c < NcI*NcJ; ++c) g0[c] *= w;
688       }
689       if (g1_func) {
690         ierr = PetscMemzero(g1, NcI*NcJ*dim * sizeof(PetscScalar));CHKERRQ(ierr);
691         g1_func(dim, Nf, NfAux, uOff, uOff_x, u, u_t, u_x, aOff, aOff_x, a, NULL, a_x, t, u_tshift, fegeom.v, numConstants, constants, g1);
692         for (c = 0; c < NcI*NcJ*dim; ++c) g1[c] *= w;
693       }
694       if (g2_func) {
695         ierr = PetscMemzero(g2, NcI*NcJ*dim * sizeof(PetscScalar));CHKERRQ(ierr);
696         g2_func(dim, Nf, NfAux, uOff, uOff_x, u, u_t, u_x, aOff, aOff_x, a, NULL, a_x, t, u_tshift, fegeom.v, numConstants, constants, g2);
697         for (c = 0; c < NcI*NcJ*dim; ++c) g2[c] *= w;
698       }
699       if (g3_func) {
700         ierr = PetscMemzero(g3, NcI*NcJ*dim*dim * sizeof(PetscScalar));CHKERRQ(ierr);
701         g3_func(dim, Nf, NfAux, uOff, uOff_x, u, u_t, u_x, aOff, aOff_x, a, NULL, a_x, t, u_tshift, fegeom.v, numConstants, constants, g3);
702         for (c = 0; c < NcI*NcJ*dim*dim; ++c) g3[c] *= w;
703       }
704 
705       ierr = PetscFEUpdateElementMat_Internal(feI, feJ, dim, NbI, NcI, BIq, DIq, basisReal, basisDerReal, NbJ, NcJ, BJq, DJq, testReal, testDerReal, &fegeom, g0, g1, g2, g3, eOffset, totDim, offsetI, offsetJ, elemMat);CHKERRQ(ierr);
706     }
707     if (debug > 1) {
708       PetscInt fc, f, gc, g;
709 
710       ierr = PetscPrintf(PETSC_COMM_SELF, "Element matrix for fields %d and %d\n", fieldI, fieldJ);CHKERRQ(ierr);
711       for (fc = 0; fc < NcI; ++fc) {
712         for (f = 0; f < NbI; ++f) {
713           const PetscInt i = offsetI + f*NcI+fc;
714           for (gc = 0; gc < NcJ; ++gc) {
715             for (g = 0; g < NbJ; ++g) {
716               const PetscInt j = offsetJ + g*NcJ+gc;
717               ierr = PetscPrintf(PETSC_COMM_SELF, "    elemMat[%d,%d,%d,%d]: %g\n", f, fc, g, gc, PetscRealPart(elemMat[eOffset+i*totDim+j]));CHKERRQ(ierr);
718             }
719           }
720           ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
721         }
722       }
723     }
724     cOffset    += totDim;
725     cOffsetAux += totDimAux;
726     eOffset    += PetscSqr(totDim);
727   }
728   PetscFunctionReturn(0);
729 }
730 
731 PetscErrorCode PetscFEIntegrateBdJacobian_Basic(PetscDS ds, PetscInt fieldI, PetscInt fieldJ, PetscInt Ne, PetscFEGeom *fgeom,
732                                                 const PetscScalar coefficients[], const PetscScalar coefficients_t[], PetscDS dsAux, const PetscScalar coefficientsAux[], PetscReal t, PetscReal u_tshift, PetscScalar elemMat[])
733 {
734   const PetscInt     debug      = 0;
735   PetscFE            feI, feJ;
736   PetscBdPointJac    g0_func, g1_func, g2_func, g3_func;
737   PetscInt           cOffset    = 0; /* Offset into coefficients[] for element e */
738   PetscInt           cOffsetAux = 0; /* Offset into coefficientsAux[] for element e */
739   PetscInt           eOffset    = 0; /* Offset into elemMat[] for element e */
740   PetscInt           offsetI    = 0; /* Offset into an element vector for fieldI */
741   PetscInt           offsetJ    = 0; /* Offset into an element vector for fieldJ */
742   PetscQuadrature    quad;
743   PetscScalar       *g0, *g1, *g2, *g3, *u, *u_t = NULL, *u_x, *a, *a_x, *basisReal, *basisDerReal, *testReal, *testDerReal;
744   const PetscScalar *constants;
745   PetscReal         *x;
746   PetscReal        **B, **D, **BAux = NULL, **DAux = NULL, *BI, *DI, *BJ, *DJ;
747   PetscInt          *uOff, *uOff_x, *aOff = NULL, *aOff_x = NULL, *Nb, *Nc, *NbAux = NULL, *NcAux = NULL;
748   PetscInt           NbI = 0, NcI = 0, NbJ = 0, NcJ = 0;
749   PetscInt           dim, numConstants, Nf, NfAux = 0, totDim, totDimAux = 0, e;
750   PetscBool          isAffine;
751   const PetscReal   *quadPoints, *quadWeights;
752   PetscInt           qNc, Nq, q, Np, dE;
753   PetscErrorCode     ierr;
754 
755   PetscFunctionBegin;
756   ierr = PetscDSGetDiscretization(ds, fieldI, (PetscObject *) &feI);CHKERRQ(ierr);
757   ierr = PetscDSGetDiscretization(ds, fieldJ, (PetscObject *) &feJ);CHKERRQ(ierr);
758   ierr = PetscFEGetSpatialDimension(feI, &dim);CHKERRQ(ierr);
759   ierr = PetscFEGetFaceQuadrature(feI, &quad);CHKERRQ(ierr);
760   ierr = PetscDSGetNumFields(ds, &Nf);CHKERRQ(ierr);
761   ierr = PetscDSGetTotalDimension(ds, &totDim);CHKERRQ(ierr);
762   ierr = PetscDSGetDimensions(ds, &Nb);CHKERRQ(ierr);
763   ierr = PetscDSGetComponents(ds, &Nc);CHKERRQ(ierr);
764   ierr = PetscDSGetComponentOffsets(ds, &uOff);CHKERRQ(ierr);
765   ierr = PetscDSGetComponentDerivativeOffsets(ds, &uOff_x);CHKERRQ(ierr);
766   ierr = PetscDSGetFieldOffset(ds, fieldI, &offsetI);CHKERRQ(ierr);
767   ierr = PetscDSGetFieldOffset(ds, fieldJ, &offsetJ);CHKERRQ(ierr);
768   ierr = PetscDSGetBdJacobian(ds, fieldI, fieldJ, &g0_func, &g1_func, &g2_func, &g3_func);CHKERRQ(ierr);
769   ierr = PetscDSGetEvaluationArrays(ds, &u, coefficients_t ? &u_t : NULL, &u_x);CHKERRQ(ierr);
770   ierr = PetscDSGetWorkspace(ds, &x, &basisReal, &basisDerReal, &testReal, &testDerReal);CHKERRQ(ierr);
771   ierr = PetscDSGetWeakFormArrays(ds, NULL, NULL, &g0, &g1, &g2, &g3);CHKERRQ(ierr);
772   ierr = PetscDSGetFaceTabulation(ds, &B, &D);CHKERRQ(ierr);
773   ierr = PetscDSGetConstants(ds, &numConstants, &constants);CHKERRQ(ierr);
774   if (dsAux) {
775     ierr = PetscDSGetNumFields(dsAux, &NfAux);CHKERRQ(ierr);
776     ierr = PetscDSGetTotalDimension(dsAux, &totDimAux);CHKERRQ(ierr);
777     ierr = PetscDSGetDimensions(dsAux, &NbAux);CHKERRQ(ierr);
778     ierr = PetscDSGetComponents(dsAux, &NcAux);CHKERRQ(ierr);
779     ierr = PetscDSGetComponentOffsets(dsAux, &aOff);CHKERRQ(ierr);
780     ierr = PetscDSGetComponentDerivativeOffsets(dsAux, &aOff_x);CHKERRQ(ierr);
781     ierr = PetscDSGetEvaluationArrays(dsAux, &a, NULL, &a_x);CHKERRQ(ierr);
782     ierr = PetscDSGetFaceTabulation(dsAux, &BAux, &DAux);CHKERRQ(ierr);
783   }
784   NbI = Nb[fieldI], NbJ = Nb[fieldJ];
785   NcI = Nc[fieldI], NcJ = Nc[fieldJ];
786   BI  = B[fieldI],  BJ  = B[fieldJ];
787   DI  = D[fieldI],  DJ  = D[fieldJ];
788   /* Initialize here in case the function is not defined */
789   ierr = PetscMemzero(g0, NcI*NcJ * sizeof(PetscScalar));CHKERRQ(ierr);
790   ierr = PetscMemzero(g1, NcI*NcJ*dim * sizeof(PetscScalar));CHKERRQ(ierr);
791   ierr = PetscMemzero(g2, NcI*NcJ*dim * sizeof(PetscScalar));CHKERRQ(ierr);
792   ierr = PetscMemzero(g3, NcI*NcJ*dim*dim * sizeof(PetscScalar));CHKERRQ(ierr);
793   ierr = PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights);CHKERRQ(ierr);
794   if (qNc != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_SUP, "Only supports scalar quadrature, not %D components\n", qNc);
795   Np = fgeom->numPoints;
796   dE = fgeom->dimEmbed;
797   isAffine = fgeom->isAffine;
798   for (e = 0; e < Ne; ++e) {
799     PetscFEGeom    fegeom;
800     const PetscInt face = fgeom->face[e][0];
801 
802     if (isAffine) {
803       fegeom.v    = x;
804       fegeom.xi   = fgeom->xi;
805       fegeom.J    = &fgeom->J[e*dE*dE];
806       fegeom.invJ = &fgeom->suppInvJ[0][e*dE*dE];
807       fegeom.detJ = &fgeom->detJ[e];
808       fegeom.n    = &fgeom->n[e*dE];
809     }
810     for (q = 0; q < Nq; ++q) {
811       const PetscReal *BIq = &BI[(face*Nq+q)*NbI*NcI],     *BJq = &BJ[(face*Nq+q)*NbJ*NcJ];
812       const PetscReal *DIq = &DI[(face*Nq+q)*NbI*NcI*dim], *DJq = &DJ[(face*Nq+q)*NbJ*NcJ*dim];
813       PetscReal  w;
814       PetscInt   c;
815 
816       if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "  quad point %d\n", q);CHKERRQ(ierr);}
817       if (isAffine) {
818         CoordinatesRefToReal(dE, dim-1, fegeom.xi, &fgeom->v[e*dE], fegeom.J, &quadPoints[q*(dim-1)], x);
819       } else {
820         fegeom.v    = &fegeom.v[(e*Np+q)*dE];
821         fegeom.invJ = &fgeom->suppInvJ[0][(e*Np+q)*dE*dE];
822         fegeom.detJ = &fgeom->detJ[e*Np+q];
823         fegeom.n    = &fgeom->n[(e*Np+q)*dE];
824       }
825       w = fegeom.detJ[0]*quadWeights[q];
826       if (coefficients) {ierr = PetscFEEvaluateFieldJets_Internal(ds, dim, Nf, Nb, Nc, face*Nq+q, B, D, &fegeom, &coefficients[cOffset], &coefficients_t[cOffset], u, u_x, u_t);CHKERRQ(ierr);}
827       if (dsAux)      {ierr = PetscFEEvaluateFieldJets_Internal(dsAux, dim, NfAux, NbAux, NcAux, face*Nq+q, BAux, DAux, &fegeom, &coefficientsAux[cOffsetAux], NULL, a, a_x, NULL);CHKERRQ(ierr);}
828       if (g0_func) {
829         ierr = PetscMemzero(g0, NcI*NcJ * sizeof(PetscScalar));CHKERRQ(ierr);
830         g0_func(dim, Nf, NfAux, uOff, uOff_x, u, u_t, u_x, aOff, aOff_x, a, NULL, a_x, t, u_tshift, fegeom.v, fegeom.n, numConstants, constants, g0);
831         for (c = 0; c < NcI*NcJ; ++c) g0[c] *= w;
832       }
833       if (g1_func) {
834         ierr = PetscMemzero(g1, NcI*NcJ*dim * sizeof(PetscScalar));CHKERRQ(ierr);
835         g1_func(dim, Nf, NfAux, uOff, uOff_x, u, u_t, u_x, aOff, aOff_x, a, NULL, a_x, t, u_tshift, fegeom.v, fegeom.n, numConstants, constants, g1);
836         for (c = 0; c < NcI*NcJ*dim; ++c) g1[c] *= w;
837       }
838       if (g2_func) {
839         ierr = PetscMemzero(g2, NcI*NcJ*dim * sizeof(PetscScalar));CHKERRQ(ierr);
840         g2_func(dim, Nf, NfAux, uOff, uOff_x, u, u_t, u_x, aOff, aOff_x, a, NULL, a_x, t, u_tshift, fegeom.v, fegeom.n, numConstants, constants, g2);
841         for (c = 0; c < NcI*NcJ*dim; ++c) g2[c] *= w;
842       }
843       if (g3_func) {
844         ierr = PetscMemzero(g3, NcI*NcJ*dim*dim * sizeof(PetscScalar));CHKERRQ(ierr);
845         g3_func(dim, Nf, NfAux, uOff, uOff_x, u, u_t, u_x, aOff, aOff_x, a, NULL, a_x, t, u_tshift, fegeom.v, fegeom.n, numConstants, constants, g3);
846         for (c = 0; c < NcI*NcJ*dim*dim; ++c) g3[c] *= w;
847       }
848 
849       ierr = PetscFEUpdateElementMat_Internal(feI, feJ, dim, NbI, NcI, BIq, DIq, basisReal, basisDerReal, NbJ, NcJ, BJq, DJq, testReal, testDerReal, &fegeom, g0, g1, g2, g3, eOffset, totDim, offsetI, offsetJ, elemMat);CHKERRQ(ierr);
850     }
851     if (debug > 1) {
852       PetscInt fc, f, gc, g;
853 
854       ierr = PetscPrintf(PETSC_COMM_SELF, "Element matrix for fields %d and %d\n", fieldI, fieldJ);CHKERRQ(ierr);
855       for (fc = 0; fc < NcI; ++fc) {
856         for (f = 0; f < NbI; ++f) {
857           const PetscInt i = offsetI + f*NcI+fc;
858           for (gc = 0; gc < NcJ; ++gc) {
859             for (g = 0; g < NbJ; ++g) {
860               const PetscInt j = offsetJ + g*NcJ+gc;
861               ierr = PetscPrintf(PETSC_COMM_SELF, "    elemMat[%d,%d,%d,%d]: %g\n", f, fc, g, gc, PetscRealPart(elemMat[eOffset+i*totDim+j]));CHKERRQ(ierr);
862             }
863           }
864           ierr = PetscPrintf(PETSC_COMM_SELF, "\n");CHKERRQ(ierr);
865         }
866       }
867     }
868     cOffset    += totDim;
869     cOffsetAux += totDimAux;
870     eOffset    += PetscSqr(totDim);
871   }
872   PetscFunctionReturn(0);
873 }
874 
875 PetscErrorCode PetscFEInitialize_Basic(PetscFE fem)
876 {
877   PetscFunctionBegin;
878   fem->ops->setfromoptions          = NULL;
879   fem->ops->setup                   = PetscFESetUp_Basic;
880   fem->ops->view                    = PetscFEView_Basic;
881   fem->ops->destroy                 = PetscFEDestroy_Basic;
882   fem->ops->getdimension            = PetscFEGetDimension_Basic;
883   fem->ops->gettabulation           = PetscFEGetTabulation_Basic;
884   fem->ops->integrate               = PetscFEIntegrate_Basic;
885   fem->ops->integratebd             = PetscFEIntegrateBd_Basic;
886   fem->ops->integrateresidual       = PetscFEIntegrateResidual_Basic;
887   fem->ops->integratebdresidual     = PetscFEIntegrateBdResidual_Basic;
888   fem->ops->integratejacobianaction = NULL/* PetscFEIntegrateJacobianAction_Basic */;
889   fem->ops->integratejacobian       = PetscFEIntegrateJacobian_Basic;
890   fem->ops->integratebdjacobian     = PetscFEIntegrateBdJacobian_Basic;
891   PetscFunctionReturn(0);
892 }
893 
894 /*MC
895   PETSCFEBASIC = "basic" - A PetscFE object that integrates with basic tiling and no vectorization
896 
897   Level: intermediate
898 
899 .seealso: PetscFEType, PetscFECreate(), PetscFESetType()
900 M*/
901 
902 PETSC_EXTERN PetscErrorCode PetscFECreate_Basic(PetscFE fem)
903 {
904   PetscFE_Basic *b;
905   PetscErrorCode ierr;
906 
907   PetscFunctionBegin;
908   PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1);
909   ierr      = PetscNewLog(fem,&b);CHKERRQ(ierr);
910   fem->data = b;
911 
912   ierr = PetscFEInitialize_Basic(fem);CHKERRQ(ierr);
913   PetscFunctionReturn(0);
914 }
915