xref: /petsc/src/dm/dt/fe/impls/basic/febasic.c (revision 9566063d113dddea24716c546802770db7481bc0)
120cf1dd8SToby Isaac #include <petsc/private/petscfeimpl.h> /*I "petscfe.h" I*/
220cf1dd8SToby Isaac #include <petscblaslapack.h>
320cf1dd8SToby Isaac 
42b99622eSMatthew G. Knepley static PetscErrorCode PetscFEDestroy_Basic(PetscFE fem)
520cf1dd8SToby Isaac {
620cf1dd8SToby Isaac   PetscFE_Basic *b = (PetscFE_Basic *) fem->data;
720cf1dd8SToby Isaac 
820cf1dd8SToby Isaac   PetscFunctionBegin;
9*9566063dSJacob Faibussowitsch   PetscCall(PetscFree(b));
1020cf1dd8SToby Isaac   PetscFunctionReturn(0);
1120cf1dd8SToby Isaac }
1220cf1dd8SToby Isaac 
132b99622eSMatthew G. Knepley static PetscErrorCode PetscFEView_Basic_Ascii(PetscFE fe, PetscViewer v)
1420cf1dd8SToby Isaac {
15d9bac1caSLisandro Dalcin   PetscInt          dim, Nc;
16d9bac1caSLisandro Dalcin   PetscSpace        basis = NULL;
17d9bac1caSLisandro Dalcin   PetscDualSpace    dual = NULL;
18d9bac1caSLisandro Dalcin   PetscQuadrature   quad = NULL;
1920cf1dd8SToby Isaac 
2020cf1dd8SToby Isaac   PetscFunctionBegin;
21*9566063dSJacob Faibussowitsch   PetscCall(PetscFEGetSpatialDimension(fe, &dim));
22*9566063dSJacob Faibussowitsch   PetscCall(PetscFEGetNumComponents(fe, &Nc));
23*9566063dSJacob Faibussowitsch   PetscCall(PetscFEGetBasisSpace(fe, &basis));
24*9566063dSJacob Faibussowitsch   PetscCall(PetscFEGetDualSpace(fe, &dual));
25*9566063dSJacob Faibussowitsch   PetscCall(PetscFEGetQuadrature(fe, &quad));
26*9566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPushTab(v));
27*9566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPrintf(v, "Basic Finite Element in %D dimensions with %D components\n",dim,Nc));
28*9566063dSJacob Faibussowitsch   if (basis) PetscCall(PetscSpaceView(basis, v));
29*9566063dSJacob Faibussowitsch   if (dual)  PetscCall(PetscDualSpaceView(dual, v));
30*9566063dSJacob Faibussowitsch   if (quad)  PetscCall(PetscQuadratureView(quad, v));
31*9566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPopTab(v));
3220cf1dd8SToby Isaac   PetscFunctionReturn(0);
3320cf1dd8SToby Isaac }
3420cf1dd8SToby Isaac 
352b99622eSMatthew G. Knepley static PetscErrorCode PetscFEView_Basic(PetscFE fe, PetscViewer v)
3620cf1dd8SToby Isaac {
3720cf1dd8SToby Isaac   PetscBool      iascii;
3820cf1dd8SToby Isaac 
3920cf1dd8SToby Isaac   PetscFunctionBegin;
40*9566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) v, PETSCVIEWERASCII, &iascii));
41*9566063dSJacob Faibussowitsch   if (iascii) PetscCall(PetscFEView_Basic_Ascii(fe, v));
4220cf1dd8SToby Isaac   PetscFunctionReturn(0);
4320cf1dd8SToby Isaac }
4420cf1dd8SToby Isaac 
4520cf1dd8SToby Isaac /* Construct the change of basis from prime basis to nodal basis */
46526996e7SStefano Zampini PETSC_INTERN PetscErrorCode PetscFESetUp_Basic(PetscFE fem)
4720cf1dd8SToby Isaac {
48b9d4cb8dSJed Brown   PetscReal     *work;
4920cf1dd8SToby Isaac   PetscBLASInt  *pivots;
5020cf1dd8SToby Isaac   PetscBLASInt   n, info;
5120cf1dd8SToby Isaac   PetscInt       pdim, j;
5220cf1dd8SToby Isaac 
5320cf1dd8SToby Isaac   PetscFunctionBegin;
54*9566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDimension(fem->dualSpace, &pdim));
55*9566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(pdim*pdim,&fem->invV));
5620cf1dd8SToby Isaac   for (j = 0; j < pdim; ++j) {
5720cf1dd8SToby Isaac     PetscReal       *Bf;
5820cf1dd8SToby Isaac     PetscQuadrature  f;
5920cf1dd8SToby Isaac     const PetscReal *points, *weights;
6020cf1dd8SToby Isaac     PetscInt         Nc, Nq, q, k, c;
6120cf1dd8SToby Isaac 
62*9566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetFunctional(fem->dualSpace, j, &f));
63*9566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureGetData(f, NULL, &Nc, &Nq, &points, &weights));
64*9566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(Nc*Nq*pdim,&Bf));
65*9566063dSJacob Faibussowitsch     PetscCall(PetscSpaceEvaluate(fem->basisSpace, Nq, points, Bf, NULL, NULL));
6620cf1dd8SToby Isaac     for (k = 0; k < pdim; ++k) {
6720cf1dd8SToby Isaac       /* V_{jk} = n_j(\phi_k) = \int \phi_k(x) n_j(x) dx */
68b9d4cb8dSJed Brown       fem->invV[j*pdim+k] = 0.0;
6920cf1dd8SToby Isaac 
7020cf1dd8SToby Isaac       for (q = 0; q < Nq; ++q) {
71b9d4cb8dSJed Brown         for (c = 0; c < Nc; ++c) fem->invV[j*pdim+k] += Bf[(q*pdim + k)*Nc + c]*weights[q*Nc + c];
7220cf1dd8SToby Isaac       }
7320cf1dd8SToby Isaac     }
74*9566063dSJacob Faibussowitsch     PetscCall(PetscFree(Bf));
7520cf1dd8SToby Isaac   }
76ea2bdf6dSBarry Smith 
77*9566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(pdim,&pivots,pdim,&work));
7820cf1dd8SToby Isaac   n = pdim;
79b9d4cb8dSJed Brown   PetscStackCallBLAS("LAPACKgetrf", LAPACKREALgetrf_(&n, &n, fem->invV, &n, pivots, &info));
8028b400f6SJacob Faibussowitsch   PetscCheck(!info,PETSC_COMM_SELF,PETSC_ERR_LIB,"Error returned from LAPACKgetrf %D",(PetscInt)info);
81b9d4cb8dSJed Brown   PetscStackCallBLAS("LAPACKgetri", LAPACKREALgetri_(&n, fem->invV, &n, pivots, work, &n, &info));
8228b400f6SJacob Faibussowitsch   PetscCheck(!info,PETSC_COMM_SELF,PETSC_ERR_LIB,"Error returned from LAPACKgetri %D",(PetscInt)info);
83*9566063dSJacob Faibussowitsch   PetscCall(PetscFree2(pivots,work));
8420cf1dd8SToby Isaac   PetscFunctionReturn(0);
8520cf1dd8SToby Isaac }
8620cf1dd8SToby Isaac 
8720cf1dd8SToby Isaac PetscErrorCode PetscFEGetDimension_Basic(PetscFE fem, PetscInt *dim)
8820cf1dd8SToby Isaac {
8920cf1dd8SToby Isaac   PetscFunctionBegin;
90*9566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDimension(fem->dualSpace, dim));
9120cf1dd8SToby Isaac   PetscFunctionReturn(0);
9220cf1dd8SToby Isaac }
9320cf1dd8SToby Isaac 
94b9d4cb8dSJed Brown /* Tensor contraction on the middle index,
95b9d4cb8dSJed Brown  *    C[m,n,p] = A[m,k,p] * B[k,n]
96b9d4cb8dSJed Brown  * where all matrices use C-style ordering.
97b9d4cb8dSJed Brown  */
98bdb10af2SPierre Jolivet static PetscErrorCode TensorContract_Private(PetscInt m,PetscInt n,PetscInt p,PetscInt k,const PetscReal *A,const PetscReal *B,PetscReal *C)
99bdb10af2SPierre Jolivet {
100b9d4cb8dSJed Brown   PetscInt i;
101b9d4cb8dSJed Brown 
102b9d4cb8dSJed Brown   PetscFunctionBegin;
103b9d4cb8dSJed Brown   for (i=0; i<m; i++) {
104b9d4cb8dSJed Brown     PetscBLASInt n_,p_,k_,lda,ldb,ldc;
105b9d4cb8dSJed Brown     PetscReal one = 1, zero = 0;
106b9d4cb8dSJed Brown     /* Taking contiguous submatrices, we wish to comput c[n,p] = a[k,p] * B[k,n]
107b9d4cb8dSJed Brown      * or, in Fortran ordering, c(p,n) = a(p,k) * B(n,k)
108b9d4cb8dSJed Brown      */
109*9566063dSJacob Faibussowitsch     PetscCall(PetscBLASIntCast(n,&n_));
110*9566063dSJacob Faibussowitsch     PetscCall(PetscBLASIntCast(p,&p_));
111*9566063dSJacob Faibussowitsch     PetscCall(PetscBLASIntCast(k,&k_));
112b9d4cb8dSJed Brown     lda = p_;
113b9d4cb8dSJed Brown     ldb = n_;
114b9d4cb8dSJed Brown     ldc = p_;
115b9d4cb8dSJed Brown     PetscStackCallBLAS("BLASgemm",BLASREALgemm_("N","T",&p_,&n_,&k_,&one,A+i*k*p,&lda,B,&ldb,&zero,C+i*n*p,&ldc));
116b9d4cb8dSJed Brown   }
117*9566063dSJacob Faibussowitsch   PetscCall(PetscLogFlops(2.*m*n*p*k));
118b9d4cb8dSJed Brown   PetscFunctionReturn(0);
119b9d4cb8dSJed Brown }
120b9d4cb8dSJed Brown 
121526996e7SStefano Zampini PETSC_INTERN PetscErrorCode PetscFECreateTabulation_Basic(PetscFE fem, PetscInt npoints, const PetscReal points[], PetscInt K, PetscTabulation T)
12220cf1dd8SToby Isaac {
12320cf1dd8SToby Isaac   DM               dm;
12420cf1dd8SToby Isaac   PetscInt         pdim; /* Dimension of FE space P */
12520cf1dd8SToby Isaac   PetscInt         dim;  /* Spatial dimension */
12620cf1dd8SToby Isaac   PetscInt         Nc;   /* Field components */
127ef0bb6c7SMatthew G. Knepley   PetscReal       *B = K >= 0 ? T->T[0] : NULL;
128ef0bb6c7SMatthew G. Knepley   PetscReal       *D = K >= 1 ? T->T[1] : NULL;
129ef0bb6c7SMatthew G. Knepley   PetscReal       *H = K >= 2 ? T->T[2] : NULL;
130ef0bb6c7SMatthew G. Knepley   PetscReal       *tmpB = NULL, *tmpD = NULL, *tmpH = NULL;
13120cf1dd8SToby Isaac 
13220cf1dd8SToby Isaac   PetscFunctionBegin;
133*9566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDM(fem->dualSpace, &dm));
134*9566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
135*9566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDimension(fem->dualSpace, &pdim));
136*9566063dSJacob Faibussowitsch   PetscCall(PetscFEGetNumComponents(fem, &Nc));
13720cf1dd8SToby Isaac   /* Evaluate the prime basis functions at all points */
138*9566063dSJacob Faibussowitsch   if (K >= 0) PetscCall(DMGetWorkArray(dm, npoints*pdim*Nc, MPIU_REAL, &tmpB));
139*9566063dSJacob Faibussowitsch   if (K >= 1) PetscCall(DMGetWorkArray(dm, npoints*pdim*Nc*dim, MPIU_REAL, &tmpD));
140*9566063dSJacob Faibussowitsch   if (K >= 2) PetscCall(DMGetWorkArray(dm, npoints*pdim*Nc*dim*dim, MPIU_REAL, &tmpH));
141*9566063dSJacob Faibussowitsch   PetscCall(PetscSpaceEvaluate(fem->basisSpace, npoints, points, tmpB, tmpD, tmpH));
142b9d4cb8dSJed Brown   /* Translate from prime to nodal basis */
14320cf1dd8SToby Isaac   if (B) {
144b9d4cb8dSJed Brown     /* B[npoints, nodes, Nc] = tmpB[npoints, prime, Nc] * invV[prime, nodes] */
145*9566063dSJacob Faibussowitsch     PetscCall(TensorContract_Private(npoints, pdim, Nc, pdim, tmpB, fem->invV, B));
14620cf1dd8SToby Isaac   }
14720cf1dd8SToby Isaac   if (D) {
148b9d4cb8dSJed Brown     /* D[npoints, nodes, Nc, dim] = tmpD[npoints, prime, Nc, dim] * invV[prime, nodes] */
149*9566063dSJacob Faibussowitsch     PetscCall(TensorContract_Private(npoints, pdim, Nc*dim, pdim, tmpD, fem->invV, D));
15020cf1dd8SToby Isaac   }
15120cf1dd8SToby Isaac   if (H) {
152b9d4cb8dSJed Brown     /* H[npoints, nodes, Nc, dim, dim] = tmpH[npoints, prime, Nc, dim, dim] * invV[prime, nodes] */
153*9566063dSJacob Faibussowitsch     PetscCall(TensorContract_Private(npoints, pdim, Nc*dim*dim, pdim, tmpH, fem->invV, H));
15420cf1dd8SToby Isaac   }
155*9566063dSJacob Faibussowitsch   if (K >= 0) PetscCall(DMRestoreWorkArray(dm, npoints*pdim*Nc, MPIU_REAL, &tmpB));
156*9566063dSJacob Faibussowitsch   if (K >= 1) PetscCall(DMRestoreWorkArray(dm, npoints*pdim*Nc*dim, MPIU_REAL, &tmpD));
157*9566063dSJacob Faibussowitsch   if (K >= 2) PetscCall(DMRestoreWorkArray(dm, npoints*pdim*Nc*dim*dim, MPIU_REAL, &tmpH));
15820cf1dd8SToby Isaac   PetscFunctionReturn(0);
15920cf1dd8SToby Isaac }
16020cf1dd8SToby Isaac 
1612b99622eSMatthew G. Knepley static PetscErrorCode PetscFEIntegrate_Basic(PetscDS ds, PetscInt field, PetscInt Ne, PetscFEGeom *cgeom,
1624bee2e38SMatthew G. Knepley                                              const PetscScalar coefficients[], PetscDS dsAux, const PetscScalar coefficientsAux[], PetscScalar integral[])
16320cf1dd8SToby Isaac {
16420cf1dd8SToby Isaac   const PetscInt     debug = 0;
1654bee2e38SMatthew G. Knepley   PetscFE            fe;
16620cf1dd8SToby Isaac   PetscPointFunc     obj_func;
16720cf1dd8SToby Isaac   PetscQuadrature    quad;
168ef0bb6c7SMatthew G. Knepley   PetscTabulation   *T, *TAux = NULL;
1694bee2e38SMatthew G. Knepley   PetscScalar       *u, *u_x, *a, *a_x;
17020cf1dd8SToby Isaac   const PetscScalar *constants;
17120cf1dd8SToby Isaac   PetscReal         *x;
172ef0bb6c7SMatthew G. Knepley   PetscInt          *uOff, *uOff_x, *aOff = NULL, *aOff_x = NULL;
17320cf1dd8SToby Isaac   PetscInt           dim, dE, Np, numConstants, Nf, NfAux = 0, totDim, totDimAux = 0, cOffset = 0, cOffsetAux = 0, e;
17420cf1dd8SToby Isaac   PetscBool          isAffine;
17520cf1dd8SToby Isaac   const PetscReal   *quadPoints, *quadWeights;
17620cf1dd8SToby Isaac   PetscInt           qNc, Nq, q;
17720cf1dd8SToby Isaac 
17820cf1dd8SToby Isaac   PetscFunctionBegin;
179*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetObjective(ds, field, &obj_func));
18020cf1dd8SToby Isaac   if (!obj_func) PetscFunctionReturn(0);
181*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetDiscretization(ds, field, (PetscObject *) &fe));
182*9566063dSJacob Faibussowitsch   PetscCall(PetscFEGetSpatialDimension(fe, &dim));
183*9566063dSJacob Faibussowitsch   PetscCall(PetscFEGetQuadrature(fe, &quad));
184*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &Nf));
185*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(ds, &totDim));
186*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponentOffsets(ds, &uOff));
187*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponentDerivativeOffsets(ds, &uOff_x));
188*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTabulation(ds, &T));
189*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetEvaluationArrays(ds, &u, NULL, &u_x));
190*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetWorkspace(ds, &x, NULL, NULL, NULL, NULL));
191*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetConstants(ds, &numConstants, &constants));
1924bee2e38SMatthew G. Knepley   if (dsAux) {
193*9566063dSJacob Faibussowitsch     PetscCall(PetscDSGetNumFields(dsAux, &NfAux));
194*9566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalDimension(dsAux, &totDimAux));
195*9566063dSJacob Faibussowitsch     PetscCall(PetscDSGetComponentOffsets(dsAux, &aOff));
196*9566063dSJacob Faibussowitsch     PetscCall(PetscDSGetComponentDerivativeOffsets(dsAux, &aOff_x));
197*9566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTabulation(dsAux, &TAux));
198*9566063dSJacob Faibussowitsch     PetscCall(PetscDSGetEvaluationArrays(dsAux, &a, NULL, &a_x));
1992c71b3e2SJacob Faibussowitsch     PetscCheckFalse(T[0]->Np != TAux[0]->Np,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of tabulation points %D != %D number of auxiliary tabulation points", T[0]->Np, TAux[0]->Np);
20020cf1dd8SToby Isaac   }
201*9566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights));
2022c71b3e2SJacob Faibussowitsch   PetscCheckFalse(qNc != 1,PETSC_COMM_SELF, PETSC_ERR_SUP, "Only supports scalar quadrature, not %D components", qNc);
20320cf1dd8SToby Isaac   Np = cgeom->numPoints;
20420cf1dd8SToby Isaac   dE = cgeom->dimEmbed;
20520cf1dd8SToby Isaac   isAffine = cgeom->isAffine;
20620cf1dd8SToby Isaac   for (e = 0; e < Ne; ++e) {
2074bee2e38SMatthew G. Knepley     PetscFEGeom fegeom;
20820cf1dd8SToby Isaac 
20927f02ce8SMatthew G. Knepley     fegeom.dim      = cgeom->dim;
21027f02ce8SMatthew G. Knepley     fegeom.dimEmbed = cgeom->dimEmbed;
21120cf1dd8SToby Isaac     if (isAffine) {
2124bee2e38SMatthew G. Knepley       fegeom.v    = x;
2134bee2e38SMatthew G. Knepley       fegeom.xi   = cgeom->xi;
2147132c3f7SMatthew G. Knepley       fegeom.J    = &cgeom->J[e*Np*dE*dE];
2157132c3f7SMatthew G. Knepley       fegeom.invJ = &cgeom->invJ[e*Np*dE*dE];
2167132c3f7SMatthew G. Knepley       fegeom.detJ = &cgeom->detJ[e*Np];
21720cf1dd8SToby Isaac     }
2184bee2e38SMatthew G. Knepley     for (q = 0; q < Nq; ++q) {
2194bee2e38SMatthew G. Knepley       PetscScalar integrand;
2204bee2e38SMatthew G. Knepley       PetscReal   w;
2214bee2e38SMatthew G. Knepley 
2224bee2e38SMatthew G. Knepley       if (isAffine) {
2237132c3f7SMatthew G. Knepley         CoordinatesRefToReal(dE, dim, fegeom.xi, &cgeom->v[e*Np*dE], fegeom.J, &quadPoints[q*dim], x);
2244bee2e38SMatthew G. Knepley       } else {
2254bee2e38SMatthew G. Knepley         fegeom.v    = &cgeom->v[(e*Np+q)*dE];
2264bee2e38SMatthew G. Knepley         fegeom.J    = &cgeom->J[(e*Np+q)*dE*dE];
2274bee2e38SMatthew G. Knepley         fegeom.invJ = &cgeom->invJ[(e*Np+q)*dE*dE];
2284bee2e38SMatthew G. Knepley         fegeom.detJ = &cgeom->detJ[e*Np+q];
2294bee2e38SMatthew G. Knepley       }
2304bee2e38SMatthew G. Knepley       w = fegeom.detJ[0]*quadWeights[q];
23120cf1dd8SToby Isaac       if (debug > 1 && q < Np) {
232*9566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "  detJ: %g\n", fegeom.detJ[0]));
2337be5e748SToby Isaac #if !defined(PETSC_USE_COMPLEX)
234*9566063dSJacob Faibussowitsch         PetscCall(DMPrintCellMatrix(e, "invJ", dim, dim, fegeom.invJ));
23520cf1dd8SToby Isaac #endif
23620cf1dd8SToby Isaac       }
237*9566063dSJacob Faibussowitsch       if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  quad point %d\n", q));
238*9566063dSJacob Faibussowitsch       PetscCall(PetscFEEvaluateFieldJets_Internal(ds, Nf, 0, q, T, &fegeom, &coefficients[cOffset], NULL, u, u_x, NULL));
239*9566063dSJacob Faibussowitsch       if (dsAux) PetscCall(PetscFEEvaluateFieldJets_Internal(dsAux, NfAux, 0, q, TAux, &fegeom, &coefficientsAux[cOffsetAux], NULL, a, a_x, NULL));
2404bee2e38SMatthew G. Knepley       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);
2414bee2e38SMatthew G. Knepley       integrand *= w;
24220cf1dd8SToby Isaac       integral[e*Nf+field] += integrand;
243*9566063dSJacob Faibussowitsch       if (debug > 1) PetscCall(PetscPrintf(PETSC_COMM_SELF, "    int: %g %g\n", (double) PetscRealPart(integrand), (double) PetscRealPart(integral[field])));
24420cf1dd8SToby Isaac     }
24520cf1dd8SToby Isaac     cOffset    += totDim;
24620cf1dd8SToby Isaac     cOffsetAux += totDimAux;
24720cf1dd8SToby Isaac   }
24820cf1dd8SToby Isaac   PetscFunctionReturn(0);
24920cf1dd8SToby Isaac }
25020cf1dd8SToby Isaac 
2512b99622eSMatthew G. Knepley static PetscErrorCode PetscFEIntegrateBd_Basic(PetscDS ds, PetscInt field,
252afe6d6adSToby Isaac                                                PetscBdPointFunc obj_func,
2534bee2e38SMatthew G. Knepley                                                PetscInt Ne, PetscFEGeom *fgeom, const PetscScalar coefficients[], PetscDS dsAux, const PetscScalar coefficientsAux[], PetscScalar integral[])
254afe6d6adSToby Isaac {
255afe6d6adSToby Isaac   const PetscInt     debug = 0;
2564bee2e38SMatthew G. Knepley   PetscFE            fe;
257afe6d6adSToby Isaac   PetscQuadrature    quad;
258ef0bb6c7SMatthew G. Knepley   PetscTabulation   *Tf, *TfAux = NULL;
2594bee2e38SMatthew G. Knepley   PetscScalar       *u, *u_x, *a, *a_x, *basisReal, *basisDerReal;
260afe6d6adSToby Isaac   const PetscScalar *constants;
261afe6d6adSToby Isaac   PetscReal         *x;
262ef0bb6c7SMatthew G. Knepley   PetscInt          *uOff, *uOff_x, *aOff = NULL, *aOff_x = NULL;
263afe6d6adSToby Isaac   PetscBool          isAffine, auxOnBd;
264afe6d6adSToby Isaac   const PetscReal   *quadPoints, *quadWeights;
265afe6d6adSToby Isaac   PetscInt           qNc, Nq, q, Np, dE;
266afe6d6adSToby Isaac   PetscInt           dim, dimAux, numConstants, Nf, NfAux = 0, totDim, totDimAux = 0, cOffset = 0, cOffsetAux = 0, e;
267afe6d6adSToby Isaac 
268afe6d6adSToby Isaac   PetscFunctionBegin;
269afe6d6adSToby Isaac   if (!obj_func) PetscFunctionReturn(0);
270*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetDiscretization(ds, field, (PetscObject *) &fe));
271*9566063dSJacob Faibussowitsch   PetscCall(PetscFEGetSpatialDimension(fe, &dim));
272*9566063dSJacob Faibussowitsch   PetscCall(PetscFEGetFaceQuadrature(fe, &quad));
273*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &Nf));
274*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(ds, &totDim));
275*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponentOffsets(ds, &uOff));
276*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponentDerivativeOffsets(ds, &uOff_x));
277*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetEvaluationArrays(ds, &u, NULL, &u_x));
278*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetWorkspace(ds, &x, &basisReal, &basisDerReal, NULL, NULL));
279*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetFaceTabulation(ds, &Tf));
280*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetConstants(ds, &numConstants, &constants));
2814bee2e38SMatthew G. Knepley   if (dsAux) {
282*9566063dSJacob Faibussowitsch     PetscCall(PetscDSGetSpatialDimension(dsAux, &dimAux));
283*9566063dSJacob Faibussowitsch     PetscCall(PetscDSGetNumFields(dsAux, &NfAux));
284*9566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalDimension(dsAux, &totDimAux));
285*9566063dSJacob Faibussowitsch     PetscCall(PetscDSGetComponentOffsets(dsAux, &aOff));
286*9566063dSJacob Faibussowitsch     PetscCall(PetscDSGetComponentDerivativeOffsets(dsAux, &aOff_x));
287*9566063dSJacob Faibussowitsch     PetscCall(PetscDSGetEvaluationArrays(dsAux, &a, NULL, &a_x));
288afe6d6adSToby Isaac     auxOnBd = dimAux < dim ? PETSC_TRUE : PETSC_FALSE;
289*9566063dSJacob Faibussowitsch     if (auxOnBd) PetscCall(PetscDSGetTabulation(dsAux, &TfAux));
290*9566063dSJacob Faibussowitsch     else         PetscCall(PetscDSGetFaceTabulation(dsAux, &TfAux));
2912c71b3e2SJacob Faibussowitsch     PetscCheckFalse(Tf[0]->Np != TfAux[0]->Np,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of tabulation points %D != %D number of auxiliary tabulation points", Tf[0]->Np, TfAux[0]->Np);
292afe6d6adSToby Isaac   }
293*9566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights));
2942c71b3e2SJacob Faibussowitsch   PetscCheckFalse(qNc != 1,PETSC_COMM_SELF, PETSC_ERR_SUP, "Only supports scalar quadrature, not %D components", qNc);
295afe6d6adSToby Isaac   Np = fgeom->numPoints;
296afe6d6adSToby Isaac   dE = fgeom->dimEmbed;
297afe6d6adSToby Isaac   isAffine = fgeom->isAffine;
298afe6d6adSToby Isaac   for (e = 0; e < Ne; ++e) {
2999f209ee4SMatthew G. Knepley     PetscFEGeom    fegeom, cgeom;
300afe6d6adSToby Isaac     const PetscInt face = fgeom->face[e][0]; /* Local face number in cell */
301ea78f98cSLisandro Dalcin     fegeom.n = NULL;
302ea78f98cSLisandro Dalcin     fegeom.v = NULL;
303ea78f98cSLisandro Dalcin     fegeom.J = NULL;
304ea78f98cSLisandro Dalcin     fegeom.detJ = NULL;
30527f02ce8SMatthew G. Knepley     fegeom.dim      = fgeom->dim;
30627f02ce8SMatthew G. Knepley     fegeom.dimEmbed = fgeom->dimEmbed;
30727f02ce8SMatthew G. Knepley     cgeom.dim       = fgeom->dim;
30827f02ce8SMatthew G. Knepley     cgeom.dimEmbed  = fgeom->dimEmbed;
3094bee2e38SMatthew G. Knepley     if (isAffine) {
3104bee2e38SMatthew G. Knepley       fegeom.v    = x;
3114bee2e38SMatthew G. Knepley       fegeom.xi   = fgeom->xi;
3127132c3f7SMatthew G. Knepley       fegeom.J    = &fgeom->J[e*Np*dE*dE];
3137132c3f7SMatthew G. Knepley       fegeom.invJ = &fgeom->invJ[e*Np*dE*dE];
3147132c3f7SMatthew G. Knepley       fegeom.detJ = &fgeom->detJ[e*Np];
3157132c3f7SMatthew G. Knepley       fegeom.n    = &fgeom->n[e*Np*dE];
3169f209ee4SMatthew G. Knepley 
3177132c3f7SMatthew G. Knepley       cgeom.J     = &fgeom->suppJ[0][e*Np*dE*dE];
3187132c3f7SMatthew G. Knepley       cgeom.invJ  = &fgeom->suppInvJ[0][e*Np*dE*dE];
3197132c3f7SMatthew G. Knepley       cgeom.detJ  = &fgeom->suppDetJ[0][e*Np];
3204bee2e38SMatthew G. Knepley     }
321afe6d6adSToby Isaac     for (q = 0; q < Nq; ++q) {
322afe6d6adSToby Isaac       PetscScalar integrand;
3234bee2e38SMatthew G. Knepley       PetscReal   w;
324afe6d6adSToby Isaac 
325afe6d6adSToby Isaac       if (isAffine) {
3267132c3f7SMatthew G. Knepley         CoordinatesRefToReal(dE, dim-1, fegeom.xi, &fgeom->v[e*Np*dE], fegeom.J, &quadPoints[q*(dim-1)], x);
327afe6d6adSToby Isaac       } else {
3283fe841f2SMatthew G. Knepley         fegeom.v    = &fgeom->v[(e*Np+q)*dE];
3299f209ee4SMatthew G. Knepley         fegeom.J    = &fgeom->J[(e*Np+q)*dE*dE];
3309f209ee4SMatthew G. Knepley         fegeom.invJ = &fgeom->invJ[(e*Np+q)*dE*dE];
3314bee2e38SMatthew G. Knepley         fegeom.detJ = &fgeom->detJ[e*Np+q];
3324bee2e38SMatthew G. Knepley         fegeom.n    = &fgeom->n[(e*Np+q)*dE];
3339f209ee4SMatthew G. Knepley 
3349f209ee4SMatthew G. Knepley         cgeom.J     = &fgeom->suppJ[0][(e*Np+q)*dE*dE];
3359f209ee4SMatthew G. Knepley         cgeom.invJ  = &fgeom->suppInvJ[0][(e*Np+q)*dE*dE];
3369f209ee4SMatthew G. Knepley         cgeom.detJ  = &fgeom->suppDetJ[0][e*Np+q];
337afe6d6adSToby Isaac       }
3384bee2e38SMatthew G. Knepley       w = fegeom.detJ[0]*quadWeights[q];
339afe6d6adSToby Isaac       if (debug > 1 && q < Np) {
340*9566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "  detJ: %g\n", fegeom.detJ[0]));
341afe6d6adSToby Isaac #ifndef PETSC_USE_COMPLEX
342*9566063dSJacob Faibussowitsch         PetscCall(DMPrintCellMatrix(e, "invJ", dim, dim, fegeom.invJ));
343afe6d6adSToby Isaac #endif
344afe6d6adSToby Isaac       }
345*9566063dSJacob Faibussowitsch       if (debug > 1) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  quad point %d\n", q));
346*9566063dSJacob Faibussowitsch       PetscCall(PetscFEEvaluateFieldJets_Internal(ds, Nf, face, q, Tf, &cgeom, &coefficients[cOffset], NULL, u, u_x, NULL));
347*9566063dSJacob Faibussowitsch       if (dsAux) PetscCall(PetscFEEvaluateFieldJets_Internal(dsAux, NfAux, face, q, TfAux, &cgeom, &coefficientsAux[cOffsetAux], NULL, a, a_x, NULL));
3484bee2e38SMatthew G. Knepley       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);
3494bee2e38SMatthew G. Knepley       integrand *= w;
350afe6d6adSToby Isaac       integral[e*Nf+field] += integrand;
351*9566063dSJacob Faibussowitsch       if (debug > 1) PetscCall(PetscPrintf(PETSC_COMM_SELF, "    int: %g %g\n", (double) PetscRealPart(integrand), (double) PetscRealPart(integral[e*Nf+field])));
352afe6d6adSToby Isaac     }
353afe6d6adSToby Isaac     cOffset    += totDim;
354afe6d6adSToby Isaac     cOffsetAux += totDimAux;
355afe6d6adSToby Isaac   }
356afe6d6adSToby Isaac   PetscFunctionReturn(0);
357afe6d6adSToby Isaac }
358afe6d6adSToby Isaac 
35906ad1575SMatthew G. Knepley PetscErrorCode PetscFEIntegrateResidual_Basic(PetscDS ds, PetscFormKey key, PetscInt Ne, PetscFEGeom *cgeom,
3604bee2e38SMatthew G. Knepley                                               const PetscScalar coefficients[], const PetscScalar coefficients_t[], PetscDS dsAux, const PetscScalar coefficientsAux[], PetscReal t, PetscScalar elemVec[])
36120cf1dd8SToby Isaac {
36220cf1dd8SToby Isaac   const PetscInt     debug = 0;
3636528b96dSMatthew G. Knepley   const PetscInt     field = key.field;
3644bee2e38SMatthew G. Knepley   PetscFE            fe;
3656528b96dSMatthew G. Knepley   PetscWeakForm      wf;
3666528b96dSMatthew G. Knepley   PetscInt           n0,       n1, i;
3676528b96dSMatthew G. Knepley   PetscPointFunc    *f0_func, *f1_func;
36820cf1dd8SToby Isaac   PetscQuadrature    quad;
369ef0bb6c7SMatthew G. Knepley   PetscTabulation   *T, *TAux = NULL;
3704bee2e38SMatthew G. Knepley   PetscScalar       *f0, *f1, *u, *u_t = NULL, *u_x, *a, *a_x, *basisReal, *basisDerReal;
37120cf1dd8SToby Isaac   const PetscScalar *constants;
37220cf1dd8SToby Isaac   PetscReal         *x;
373ef0bb6c7SMatthew G. Knepley   PetscInt          *uOff, *uOff_x, *aOff = NULL, *aOff_x = NULL;
374ef0bb6c7SMatthew G. Knepley   PetscInt           dim, numConstants, Nf, NfAux = 0, totDim, totDimAux = 0, cOffset = 0, cOffsetAux = 0, fOffset, e;
37520cf1dd8SToby Isaac   const PetscReal   *quadPoints, *quadWeights;
3766587ee25SMatthew G. Knepley   PetscInt           qdim, qNc, Nq, q, dE;
37720cf1dd8SToby Isaac 
37820cf1dd8SToby Isaac   PetscFunctionBegin;
379*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetDiscretization(ds, field, (PetscObject *) &fe));
380*9566063dSJacob Faibussowitsch   PetscCall(PetscFEGetSpatialDimension(fe, &dim));
381*9566063dSJacob Faibussowitsch   PetscCall(PetscFEGetQuadrature(fe, &quad));
382*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &Nf));
383*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(ds, &totDim));
384*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponentOffsets(ds, &uOff));
385*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponentDerivativeOffsets(ds, &uOff_x));
386*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetFieldOffset(ds, field, &fOffset));
387*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetWeakForm(ds, &wf));
388*9566063dSJacob Faibussowitsch   PetscCall(PetscWeakFormGetResidual(wf, key.label, key.value, key.field, key.part, &n0, &f0_func, &n1, &f1_func));
3896528b96dSMatthew G. Knepley   if (!n0 && !n1) PetscFunctionReturn(0);
390*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetEvaluationArrays(ds, &u, coefficients_t ? &u_t : NULL, &u_x));
391*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetWorkspace(ds, &x, &basisReal, &basisDerReal, NULL, NULL));
392*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetWeakFormArrays(ds, &f0, &f1, NULL, NULL, NULL, NULL));
393*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTabulation(ds, &T));
394*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetConstants(ds, &numConstants, &constants));
3954bee2e38SMatthew G. Knepley   if (dsAux) {
396*9566063dSJacob Faibussowitsch     PetscCall(PetscDSGetNumFields(dsAux, &NfAux));
397*9566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalDimension(dsAux, &totDimAux));
398*9566063dSJacob Faibussowitsch     PetscCall(PetscDSGetComponentOffsets(dsAux, &aOff));
399*9566063dSJacob Faibussowitsch     PetscCall(PetscDSGetComponentDerivativeOffsets(dsAux, &aOff_x));
400*9566063dSJacob Faibussowitsch     PetscCall(PetscDSGetEvaluationArrays(dsAux, &a, NULL, &a_x));
401*9566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTabulation(dsAux, &TAux));
4022c71b3e2SJacob Faibussowitsch     PetscCheckFalse(T[0]->Np != TAux[0]->Np,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of tabulation points %D != %D number of auxiliary tabulation points", T[0]->Np, TAux[0]->Np);
40320cf1dd8SToby Isaac   }
404*9566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(quad, &qdim, &qNc, &Nq, &quadPoints, &quadWeights));
4052c71b3e2SJacob Faibussowitsch   PetscCheckFalse(qNc != 1,PETSC_COMM_SELF, PETSC_ERR_SUP, "Only supports scalar quadrature, not %D components", qNc);
40620cf1dd8SToby Isaac   dE = cgeom->dimEmbed;
4072c71b3e2SJacob Faibussowitsch   PetscCheckFalse(cgeom->dim != qdim,PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "FEGeom dim %D != %D quadrature dim", cgeom->dim, qdim);
40820cf1dd8SToby Isaac   for (e = 0; e < Ne; ++e) {
4094bee2e38SMatthew G. Knepley     PetscFEGeom fegeom;
41020cf1dd8SToby Isaac 
4116587ee25SMatthew G. Knepley     fegeom.v = x; /* workspace */
412*9566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(f0, Nq*T[field]->Nc));
413*9566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(f1, Nq*T[field]->Nc*dE));
41420cf1dd8SToby Isaac     for (q = 0; q < Nq; ++q) {
4154bee2e38SMatthew G. Knepley       PetscReal w;
4164bee2e38SMatthew G. Knepley       PetscInt  c, d;
41720cf1dd8SToby Isaac 
418*9566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomGetPoint(cgeom, e, q, &quadPoints[q*cgeom->dim], &fegeom));
4194bee2e38SMatthew G. Knepley       w = fegeom.detJ[0]*quadWeights[q];
4206587ee25SMatthew G. Knepley       if (debug > 1 && q < cgeom->numPoints) {
421*9566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "  detJ: %g\n", fegeom.detJ[0]));
4227be5e748SToby Isaac #if !defined(PETSC_USE_COMPLEX)
423*9566063dSJacob Faibussowitsch         PetscCall(DMPrintCellMatrix(e, "invJ", dim, dim, fegeom.invJ));
42420cf1dd8SToby Isaac #endif
42520cf1dd8SToby Isaac       }
426*9566063dSJacob Faibussowitsch       PetscCall(PetscFEEvaluateFieldJets_Internal(ds, Nf, 0, q, T, &fegeom, &coefficients[cOffset], &coefficients_t[cOffset], u, u_x, u_t));
427*9566063dSJacob Faibussowitsch       if (dsAux) PetscCall(PetscFEEvaluateFieldJets_Internal(dsAux, NfAux, 0, q, TAux, &fegeom, &coefficientsAux[cOffsetAux], NULL, a, a_x, NULL));
4286528b96dSMatthew G. Knepley       for (i = 0; i < n0; ++i) f0_func[i](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*T[field]->Nc]);
429ef0bb6c7SMatthew G. Knepley       for (c = 0; c < T[field]->Nc; ++c) f0[q*T[field]->Nc+c] *= w;
4306528b96dSMatthew G. Knepley       for (i = 0; i < n1; ++i) f1_func[i](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*T[field]->Nc*dim]);
431ef0bb6c7SMatthew G. Knepley       for (c = 0; c < T[field]->Nc; ++c) for (d = 0; d < dim; ++d) f1[(q*T[field]->Nc+c)*dim+d] *= w;
432b8025e53SMatthew G. Knepley       if (debug) {
433*9566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "  quad point %d wt %g\n", q, quadWeights[q]));
434b8025e53SMatthew G. Knepley         if (debug > 2) {
435*9566063dSJacob Faibussowitsch           PetscCall(PetscPrintf(PETSC_COMM_SELF, "  field %d:", field));
436*9566063dSJacob Faibussowitsch           for (c = 0; c < T[field]->Nc; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %g", u[uOff[field]+c]));
437*9566063dSJacob Faibussowitsch           PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
438*9566063dSJacob Faibussowitsch           PetscCall(PetscPrintf(PETSC_COMM_SELF, "  resid %d:", field));
439*9566063dSJacob Faibussowitsch           for (c = 0; c < T[field]->Nc; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %g", f0[q*T[field]->Nc+c]));
440*9566063dSJacob Faibussowitsch           PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
441b8025e53SMatthew G. Knepley         }
442b8025e53SMatthew G. Knepley       }
44320cf1dd8SToby Isaac     }
444*9566063dSJacob Faibussowitsch     PetscCall(PetscFEUpdateElementVec_Internal(fe, T[field], 0, basisReal, basisDerReal, e, cgeom, f0, f1, &elemVec[cOffset+fOffset]));
44520cf1dd8SToby Isaac     cOffset    += totDim;
44620cf1dd8SToby Isaac     cOffsetAux += totDimAux;
44720cf1dd8SToby Isaac   }
44820cf1dd8SToby Isaac   PetscFunctionReturn(0);
44920cf1dd8SToby Isaac }
45020cf1dd8SToby Isaac 
45106ad1575SMatthew G. Knepley PetscErrorCode PetscFEIntegrateBdResidual_Basic(PetscDS ds, PetscWeakForm wf, PetscFormKey key, PetscInt Ne, PetscFEGeom *fgeom,
4524bee2e38SMatthew G. Knepley                                                 const PetscScalar coefficients[], const PetscScalar coefficients_t[], PetscDS dsAux, const PetscScalar coefficientsAux[], PetscReal t, PetscScalar elemVec[])
45320cf1dd8SToby Isaac {
45420cf1dd8SToby Isaac   const PetscInt     debug = 0;
45506d8a0d3SMatthew G. Knepley   const PetscInt     field = key.field;
4564bee2e38SMatthew G. Knepley   PetscFE            fe;
45706d8a0d3SMatthew G. Knepley   PetscInt           n0,       n1, i;
45806d8a0d3SMatthew G. Knepley   PetscBdPointFunc  *f0_func, *f1_func;
45920cf1dd8SToby Isaac   PetscQuadrature    quad;
460ef0bb6c7SMatthew G. Knepley   PetscTabulation   *Tf, *TfAux = NULL;
4614bee2e38SMatthew G. Knepley   PetscScalar       *f0, *f1, *u, *u_t = NULL, *u_x, *a, *a_x, *basisReal, *basisDerReal;
46220cf1dd8SToby Isaac   const PetscScalar *constants;
46320cf1dd8SToby Isaac   PetscReal         *x;
464ef0bb6c7SMatthew G. Knepley   PetscInt          *uOff, *uOff_x, *aOff = NULL, *aOff_x = NULL;
465ef0bb6c7SMatthew G. Knepley   PetscInt           dim, dimAux, numConstants, Nf, NfAux = 0, totDim, totDimAux = 0, cOffset = 0, cOffsetAux = 0, fOffset, e, NcI;
4666587ee25SMatthew G. Knepley   PetscBool          auxOnBd = PETSC_FALSE;
46720cf1dd8SToby Isaac   const PetscReal   *quadPoints, *quadWeights;
4686587ee25SMatthew G. Knepley   PetscInt           qdim, qNc, Nq, q, dE;
46920cf1dd8SToby Isaac 
47020cf1dd8SToby Isaac   PetscFunctionBegin;
471*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetDiscretization(ds, field, (PetscObject *) &fe));
472*9566063dSJacob Faibussowitsch   PetscCall(PetscFEGetSpatialDimension(fe, &dim));
473*9566063dSJacob Faibussowitsch   PetscCall(PetscFEGetFaceQuadrature(fe, &quad));
474*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &Nf));
475*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(ds, &totDim));
476*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponentOffsets(ds, &uOff));
477*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponentDerivativeOffsets(ds, &uOff_x));
478*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetFieldOffset(ds, field, &fOffset));
479*9566063dSJacob Faibussowitsch   PetscCall(PetscWeakFormGetBdResidual(wf, key.label, key.value, key.field, key.part, &n0, &f0_func, &n1, &f1_func));
48006d8a0d3SMatthew G. Knepley   if (!n0 && !n1) PetscFunctionReturn(0);
481*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetEvaluationArrays(ds, &u, coefficients_t ? &u_t : NULL, &u_x));
482*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetWorkspace(ds, &x, &basisReal, &basisDerReal, NULL, NULL));
483*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetWeakFormArrays(ds, &f0, &f1, NULL, NULL, NULL, NULL));
484*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetFaceTabulation(ds, &Tf));
485*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetConstants(ds, &numConstants, &constants));
4864bee2e38SMatthew G. Knepley   if (dsAux) {
487*9566063dSJacob Faibussowitsch     PetscCall(PetscDSGetSpatialDimension(dsAux, &dimAux));
488*9566063dSJacob Faibussowitsch     PetscCall(PetscDSGetNumFields(dsAux, &NfAux));
489*9566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalDimension(dsAux, &totDimAux));
490*9566063dSJacob Faibussowitsch     PetscCall(PetscDSGetComponentOffsets(dsAux, &aOff));
491*9566063dSJacob Faibussowitsch     PetscCall(PetscDSGetComponentDerivativeOffsets(dsAux, &aOff_x));
492*9566063dSJacob Faibussowitsch     PetscCall(PetscDSGetEvaluationArrays(dsAux, &a, NULL, &a_x));
4937be5e748SToby Isaac     auxOnBd = dimAux < dim ? PETSC_TRUE : PETSC_FALSE;
494*9566063dSJacob Faibussowitsch     if (auxOnBd) PetscCall(PetscDSGetTabulation(dsAux, &TfAux));
495*9566063dSJacob Faibussowitsch     else         PetscCall(PetscDSGetFaceTabulation(dsAux, &TfAux));
4962c71b3e2SJacob Faibussowitsch     PetscCheckFalse(Tf[0]->Np != TfAux[0]->Np,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of tabulation points %D != %D number of auxiliary tabulation points", Tf[0]->Np, TfAux[0]->Np);
49720cf1dd8SToby Isaac   }
498ef0bb6c7SMatthew G. Knepley   NcI = Tf[field]->Nc;
499*9566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(quad, &qdim, &qNc, &Nq, &quadPoints, &quadWeights));
5002c71b3e2SJacob Faibussowitsch   PetscCheckFalse(qNc != 1,PETSC_COMM_SELF, PETSC_ERR_SUP, "Only supports scalar quadrature, not %D components", qNc);
50120cf1dd8SToby Isaac   dE = fgeom->dimEmbed;
5026587ee25SMatthew G. Knepley   /* TODO FIX THIS */
5036587ee25SMatthew G. Knepley   fgeom->dim = dim-1;
5042c71b3e2SJacob Faibussowitsch   PetscCheckFalse(fgeom->dim != qdim,PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "FEGeom dim %D != %D quadrature dim", fgeom->dim, qdim);
50520cf1dd8SToby Isaac   for (e = 0; e < Ne; ++e) {
5069f209ee4SMatthew G. Knepley     PetscFEGeom    fegeom, cgeom;
50720cf1dd8SToby Isaac     const PetscInt face = fgeom->face[e][0];
5089f209ee4SMatthew G. Knepley 
5096587ee25SMatthew G. Knepley     fegeom.v = x; /* Workspace */
510*9566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(f0, Nq*NcI));
511*9566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(f1, Nq*NcI*dE));
51220cf1dd8SToby Isaac     for (q = 0; q < Nq; ++q) {
5134bee2e38SMatthew G. Knepley       PetscReal w;
5144bee2e38SMatthew G. Knepley       PetscInt  c, d;
5154bee2e38SMatthew G. Knepley 
516*9566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomGetPoint(fgeom, e, q, &quadPoints[q*fgeom->dim], &fegeom));
517*9566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomGetCellPoint(fgeom, e, q, &cgeom));
5184bee2e38SMatthew G. Knepley       w = fegeom.detJ[0]*quadWeights[q];
51962bd480fSMatthew G. Knepley       if (debug > 1) {
5206587ee25SMatthew G. Knepley         if ((fgeom->isAffine && q == 0) || (!fgeom->isAffine)) {
521*9566063dSJacob Faibussowitsch           PetscCall(PetscPrintf(PETSC_COMM_SELF, "  detJ: %g\n", fegeom.detJ[0]));
5227be5e748SToby Isaac #if !defined(PETSC_USE_COMPLEX)
523*9566063dSJacob Faibussowitsch           PetscCall(DMPrintCellMatrix(e, "invJ", dim, dim, fegeom.invJ));
524*9566063dSJacob Faibussowitsch           PetscCall(DMPrintCellVector(e, "n", dim, fegeom.n));
52520cf1dd8SToby Isaac #endif
52620cf1dd8SToby Isaac         }
52762bd480fSMatthew G. Knepley       }
528*9566063dSJacob Faibussowitsch       PetscCall(PetscFEEvaluateFieldJets_Internal(ds, Nf, face, q, Tf, &cgeom, &coefficients[cOffset], &coefficients_t[cOffset], u, u_x, u_t));
529*9566063dSJacob Faibussowitsch       if (dsAux) PetscCall(PetscFEEvaluateFieldJets_Internal(dsAux, NfAux, auxOnBd ? 0 : face, q, TfAux, &cgeom, &coefficientsAux[cOffsetAux], NULL, a, a_x, NULL));
53006d8a0d3SMatthew G. Knepley       for (i = 0; i < n0; ++i) f0_func[i](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]);
5314bee2e38SMatthew G. Knepley       for (c = 0; c < NcI; ++c) f0[q*NcI+c] *= w;
53206d8a0d3SMatthew G. Knepley       for (i = 0; i < n1; ++i) f1_func[i](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]);
5334bee2e38SMatthew G. Knepley       for (c = 0; c < NcI; ++c) for (d = 0; d < dim; ++d) f1[(q*NcI+c)*dim+d] *= w;
53462bd480fSMatthew G. Knepley       if (debug) {
535*9566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "  elem %D quad point %d\n", e, q));
53662bd480fSMatthew G. Knepley         for (c = 0; c < NcI; ++c) {
537*9566063dSJacob Faibussowitsch           if (n0) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  f0[%D] %g\n", c, f0[q*NcI+c]));
53862bd480fSMatthew G. Knepley           if (n1) {
539*9566063dSJacob Faibussowitsch             for (d = 0; d < dim; ++d) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  f1[%D,%D] %g", c, d, f1[(q*NcI + c)*dim + d]));
540*9566063dSJacob Faibussowitsch             PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
54162bd480fSMatthew G. Knepley           }
54262bd480fSMatthew G. Knepley         }
54362bd480fSMatthew G. Knepley       }
54420cf1dd8SToby Isaac     }
545*9566063dSJacob Faibussowitsch     PetscCall(PetscFEUpdateElementVec_Internal(fe, Tf[field], face, basisReal, basisDerReal, e, fgeom, f0, f1, &elemVec[cOffset+fOffset]));
54620cf1dd8SToby Isaac     cOffset    += totDim;
54720cf1dd8SToby Isaac     cOffsetAux += totDimAux;
54820cf1dd8SToby Isaac   }
54920cf1dd8SToby Isaac   PetscFunctionReturn(0);
55020cf1dd8SToby Isaac }
55120cf1dd8SToby Isaac 
55227f02ce8SMatthew G. Knepley /*
55327f02ce8SMatthew G. Knepley   BdIntegral: Operates completely in the embedding dimension. The trick is to have special "face quadrature" so we only integrate over the face, but
55427f02ce8SMatthew G. Knepley               all transforms operate in the full space and are square.
55527f02ce8SMatthew G. Knepley 
55627f02ce8SMatthew G. Knepley   HybridIntegral: The discretization is lower dimensional. That means the transforms are non-square.
55727f02ce8SMatthew G. Knepley     1) DMPlexGetCellFields() retrieves from the hybrid cell, so it gets fields from both faces
55827f02ce8SMatthew G. Knepley     2) We need to assume that the orientation is 0 for both
55927f02ce8SMatthew G. Knepley     3) TODO We need to use a non-square Jacobian for the derivative maps, meaning the embedding dimension has to go to EvaluateFieldJets() and UpdateElementVec()
56027f02ce8SMatthew G. Knepley */
561c2b7495fSMatthew G. Knepley static PetscErrorCode PetscFEIntegrateHybridResidual_Basic(PetscDS ds, PetscFormKey key, PetscInt s, PetscInt Ne, PetscFEGeom *fgeom,
56227f02ce8SMatthew G. Knepley                                                            const PetscScalar coefficients[], const PetscScalar coefficients_t[], PetscDS dsAux, const PetscScalar coefficientsAux[], PetscReal t, PetscScalar elemVec[])
56327f02ce8SMatthew G. Knepley {
56427f02ce8SMatthew G. Knepley   const PetscInt     debug = 0;
5656528b96dSMatthew G. Knepley   const PetscInt     field = key.field;
56627f02ce8SMatthew G. Knepley   PetscFE            fe;
5676528b96dSMatthew G. Knepley   PetscWeakForm      wf;
5686528b96dSMatthew G. Knepley   PetscInt           n0,      n1, i;
5696528b96dSMatthew G. Knepley   PetscBdPointFunc  *f0_func, *f1_func;
57027f02ce8SMatthew G. Knepley   PetscQuadrature    quad;
571665f567fSMatthew G. Knepley   PetscTabulation   *Tf, *TfAux = NULL;
57227f02ce8SMatthew G. Knepley   PetscScalar       *f0, *f1, *u, *u_t = NULL, *u_x, *a, *a_x, *basisReal, *basisDerReal;
57327f02ce8SMatthew G. Knepley   const PetscScalar *constants;
57427f02ce8SMatthew G. Knepley   PetscReal         *x;
575665f567fSMatthew G. Knepley   PetscInt          *uOff, *uOff_x, *aOff = NULL, *aOff_x = NULL;
576665f567fSMatthew G. Knepley   PetscInt           dim, dimAux, numConstants, Nf, NfAux = 0, totDim, totDimAux = 0, cOffset = 0, cOffsetAux = 0, fOffset, e, NcI, NcS;
5776587ee25SMatthew G. Knepley   PetscBool          isCohesiveField, auxOnBd = PETSC_FALSE;
57827f02ce8SMatthew G. Knepley   const PetscReal   *quadPoints, *quadWeights;
5796587ee25SMatthew G. Knepley   PetscInt           qdim, qNc, Nq, q, dE;
58027f02ce8SMatthew G. Knepley 
58127f02ce8SMatthew G. Knepley   PetscFunctionBegin;
58227f02ce8SMatthew G. Knepley   /* Hybrid discretization is posed directly on faces */
583*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetDiscretization(ds, field, (PetscObject *) &fe));
584*9566063dSJacob Faibussowitsch   PetscCall(PetscFEGetSpatialDimension(fe, &dim));
585*9566063dSJacob Faibussowitsch   PetscCall(PetscFEGetQuadrature(fe, &quad));
586*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &Nf));
587*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(ds, &totDim));
588*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponentOffsetsCohesive(ds, s, &uOff));
589*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponentDerivativeOffsetsCohesive(ds, s, &uOff_x));
590*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetFieldOffsetCohesive(ds, field, &fOffset));
591*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetWeakForm(ds, &wf));
592*9566063dSJacob Faibussowitsch   PetscCall(PetscWeakFormGetBdResidual(wf, key.label, key.value, key.field, key.part, &n0, &f0_func, &n1, &f1_func));
5936528b96dSMatthew G. Knepley   if (!n0 && !n1) PetscFunctionReturn(0);
594*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetEvaluationArrays(ds, &u, coefficients_t ? &u_t : NULL, &u_x));
595*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetWorkspace(ds, &x, &basisReal, &basisDerReal, NULL, NULL));
596*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetWeakFormArrays(ds, &f0, &f1, NULL, NULL, NULL, NULL));
59727f02ce8SMatthew G. Knepley   /* NOTE This is a bulk tabulation because the DS is a face discretization */
598*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTabulation(ds, &Tf));
599*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetConstants(ds, &numConstants, &constants));
60027f02ce8SMatthew G. Knepley   if (dsAux) {
601*9566063dSJacob Faibussowitsch     PetscCall(PetscDSGetSpatialDimension(dsAux, &dimAux));
602*9566063dSJacob Faibussowitsch     PetscCall(PetscDSGetNumFields(dsAux, &NfAux));
603*9566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalDimension(dsAux, &totDimAux));
604*9566063dSJacob Faibussowitsch     PetscCall(PetscDSGetComponentOffsets(dsAux, &aOff));
605*9566063dSJacob Faibussowitsch     PetscCall(PetscDSGetComponentDerivativeOffsets(dsAux, &aOff_x));
606*9566063dSJacob Faibussowitsch     PetscCall(PetscDSGetEvaluationArrays(dsAux, &a, NULL, &a_x));
60701907d53SMatthew G. Knepley     auxOnBd = dimAux == dim ? PETSC_TRUE : PETSC_FALSE;
608*9566063dSJacob Faibussowitsch     if (auxOnBd) PetscCall(PetscDSGetTabulation(dsAux, &TfAux));
609*9566063dSJacob Faibussowitsch     else         PetscCall(PetscDSGetFaceTabulation(dsAux, &TfAux));
6102c71b3e2SJacob Faibussowitsch     PetscCheckFalse(Tf[0]->Np != TfAux[0]->Np,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of tabulation points %D != %D number of auxiliary tabulation points", Tf[0]->Np, TfAux[0]->Np);
61127f02ce8SMatthew G. Knepley   }
612*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetCohesive(ds, field, &isCohesiveField));
613665f567fSMatthew G. Knepley   NcI = Tf[field]->Nc;
614c2b7495fSMatthew G. Knepley   NcS = NcI;
615*9566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(quad, &qdim, &qNc, &Nq, &quadPoints, &quadWeights));
6162c71b3e2SJacob Faibussowitsch   PetscCheckFalse(qNc != 1,PETSC_COMM_SELF, PETSC_ERR_SUP, "Only supports scalar quadrature, not %D components", qNc);
61727f02ce8SMatthew G. Knepley   dE = fgeom->dimEmbed;
6182c71b3e2SJacob Faibussowitsch   PetscCheckFalse(fgeom->dim != qdim,PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "FEGeom dim %D != %D quadrature dim", fgeom->dim, qdim);
61927f02ce8SMatthew G. Knepley   for (e = 0; e < Ne; ++e) {
62027f02ce8SMatthew G. Knepley     PetscFEGeom    fegeom;
62127f02ce8SMatthew G. Knepley     const PetscInt face = fgeom->face[e][0];
62227f02ce8SMatthew G. Knepley 
6236587ee25SMatthew G. Knepley     fegeom.v = x; /* Workspace */
624*9566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(f0, Nq*NcS));
625*9566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(f1, Nq*NcS*dE));
62627f02ce8SMatthew G. Knepley     for (q = 0; q < Nq; ++q) {
62727f02ce8SMatthew G. Knepley       PetscReal w;
62827f02ce8SMatthew G. Knepley       PetscInt  c, d;
62927f02ce8SMatthew G. Knepley 
630*9566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomGetPoint(fgeom, e, q, &quadPoints[q*fgeom->dim], &fegeom));
63127f02ce8SMatthew G. Knepley       w = fegeom.detJ[0]*quadWeights[q];
6326587ee25SMatthew G. Knepley       if (debug > 1 && q < fgeom->numPoints) {
633*9566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "  detJ: %g\n", fegeom.detJ[0]));
63427f02ce8SMatthew G. Knepley #if !defined(PETSC_USE_COMPLEX)
635*9566063dSJacob Faibussowitsch         PetscCall(DMPrintCellMatrix(e, "invJ", dim, dE, fegeom.invJ));
63627f02ce8SMatthew G. Knepley #endif
63727f02ce8SMatthew G. Knepley       }
638*9566063dSJacob Faibussowitsch       if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  quad point %d\n", q));
63927f02ce8SMatthew G. Knepley       /* TODO Is this cell or face quadrature, meaning should we use 'q' or 'face*Nq+q' */
640*9566063dSJacob Faibussowitsch       PetscCall(PetscFEEvaluateFieldJets_Hybrid_Internal(ds, Nf, 0, q, Tf, &fegeom, &coefficients[cOffset], &coefficients_t[cOffset], u, u_x, u_t));
641*9566063dSJacob Faibussowitsch       if (dsAux) PetscCall(PetscFEEvaluateFieldJets_Internal(dsAux, NfAux, 0, auxOnBd ? q : face*Nq+q, TfAux, &fegeom, &coefficientsAux[cOffsetAux], NULL, a, a_x, NULL));
6426528b96dSMatthew G. Knepley       for (i = 0; i < n0; ++i) f0_func[i](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*NcS]);
64327f02ce8SMatthew G. Knepley       for (c = 0; c < NcS; ++c) f0[q*NcS+c] *= w;
6449ee2af8cSMatthew G. Knepley       for (i = 0; i < n1; ++i) f1_func[i](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*NcS*dE]);
6459ee2af8cSMatthew G. Knepley       for (c = 0; c < NcS; ++c) for (d = 0; d < dE; ++d) f1[(q*NcS+c)*dE+d] *= w;
64627f02ce8SMatthew G. Knepley     }
6475fedec97SMatthew G. Knepley     if (isCohesiveField) {PetscFEUpdateElementVec_Internal(fe, Tf[field], 0, basisReal, basisDerReal, e, fgeom, f0, f1, &elemVec[cOffset+fOffset]);}
6485fedec97SMatthew G. Knepley     else                 {PetscFEUpdateElementVec_Hybrid_Internal(fe, Tf[field], 0, s, basisReal, basisDerReal, fgeom, f0, f1, &elemVec[cOffset+fOffset]);}
64927f02ce8SMatthew G. Knepley     cOffset    += totDim;
65027f02ce8SMatthew G. Knepley     cOffsetAux += totDimAux;
65127f02ce8SMatthew G. Knepley   }
65227f02ce8SMatthew G. Knepley   PetscFunctionReturn(0);
65327f02ce8SMatthew G. Knepley }
65427f02ce8SMatthew G. Knepley 
65506ad1575SMatthew G. Knepley PetscErrorCode PetscFEIntegrateJacobian_Basic(PetscDS ds, PetscFEJacobianType jtype, PetscFormKey key, PetscInt Ne, PetscFEGeom *cgeom,
6564bee2e38SMatthew G. Knepley                                               const PetscScalar coefficients[], const PetscScalar coefficients_t[], PetscDS dsAux, const PetscScalar coefficientsAux[], PetscReal t, PetscReal u_tshift, PetscScalar elemMat[])
65720cf1dd8SToby Isaac {
65820cf1dd8SToby Isaac   const PetscInt     debug      = 0;
6594bee2e38SMatthew G. Knepley   PetscFE            feI, feJ;
6606528b96dSMatthew G. Knepley   PetscWeakForm      wf;
6616528b96dSMatthew G. Knepley   PetscPointJac     *g0_func, *g1_func, *g2_func, *g3_func;
6626528b96dSMatthew G. Knepley   PetscInt           n0, n1, n2, n3, i;
66320cf1dd8SToby Isaac   PetscInt           cOffset    = 0; /* Offset into coefficients[] for element e */
66420cf1dd8SToby Isaac   PetscInt           cOffsetAux = 0; /* Offset into coefficientsAux[] for element e */
66520cf1dd8SToby Isaac   PetscInt           eOffset    = 0; /* Offset into elemMat[] for element e */
66620cf1dd8SToby Isaac   PetscInt           offsetI    = 0; /* Offset into an element vector for fieldI */
66720cf1dd8SToby Isaac   PetscInt           offsetJ    = 0; /* Offset into an element vector for fieldJ */
66820cf1dd8SToby Isaac   PetscQuadrature    quad;
669ef0bb6c7SMatthew G. Knepley   PetscTabulation   *T, *TAux = NULL;
6704bee2e38SMatthew G. Knepley   PetscScalar       *g0, *g1, *g2, *g3, *u, *u_t = NULL, *u_x, *a, *a_x, *basisReal, *basisDerReal, *testReal, *testDerReal;
67120cf1dd8SToby Isaac   const PetscScalar *constants;
67220cf1dd8SToby Isaac   PetscReal         *x;
673ef0bb6c7SMatthew G. Knepley   PetscInt          *uOff, *uOff_x, *aOff = NULL, *aOff_x = NULL;
674ef0bb6c7SMatthew G. Knepley   PetscInt           NcI = 0, NcJ = 0;
6756528b96dSMatthew G. Knepley   PetscInt           dim, numConstants, Nf, fieldI, fieldJ, NfAux = 0, totDim, totDimAux = 0, e;
67620cf1dd8SToby Isaac   PetscInt           dE, Np;
67720cf1dd8SToby Isaac   PetscBool          isAffine;
67820cf1dd8SToby Isaac   const PetscReal   *quadPoints, *quadWeights;
67920cf1dd8SToby Isaac   PetscInt           qNc, Nq, q;
68020cf1dd8SToby Isaac 
68120cf1dd8SToby Isaac   PetscFunctionBegin;
682*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &Nf));
6836528b96dSMatthew G. Knepley   fieldI = key.field / Nf;
6846528b96dSMatthew G. Knepley   fieldJ = key.field % Nf;
685*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetDiscretization(ds, fieldI, (PetscObject *) &feI));
686*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetDiscretization(ds, fieldJ, (PetscObject *) &feJ));
687*9566063dSJacob Faibussowitsch   PetscCall(PetscFEGetSpatialDimension(feI, &dim));
688*9566063dSJacob Faibussowitsch   PetscCall(PetscFEGetQuadrature(feI, &quad));
689*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(ds, &totDim));
690*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponentOffsets(ds, &uOff));
691*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponentDerivativeOffsets(ds, &uOff_x));
692*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetWeakForm(ds, &wf));
69320cf1dd8SToby Isaac   switch(jtype) {
694*9566063dSJacob Faibussowitsch   case PETSCFE_JACOBIAN_DYN: PetscCall(PetscWeakFormGetDynamicJacobian(wf, key.label, key.value, fieldI, fieldJ, key.part, &n0, &g0_func, &n1, &g1_func, &n2, &g2_func, &n3, &g3_func));break;
695*9566063dSJacob Faibussowitsch   case PETSCFE_JACOBIAN_PRE: PetscCall(PetscWeakFormGetJacobianPreconditioner(wf, key.label, key.value, fieldI, fieldJ, key.part, &n0, &g0_func, &n1, &g1_func, &n2, &g2_func, &n3, &g3_func));break;
696*9566063dSJacob Faibussowitsch   case PETSCFE_JACOBIAN:     PetscCall(PetscWeakFormGetJacobian(wf, key.label, key.value, fieldI, fieldJ, key.part, &n0, &g0_func, &n1, &g1_func, &n2, &g2_func, &n3, &g3_func));break;
69720cf1dd8SToby Isaac   }
6986528b96dSMatthew G. Knepley   if (!n0 && !n1 && !n2 && !n3) PetscFunctionReturn(0);
699*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetEvaluationArrays(ds, &u, coefficients_t ? &u_t : NULL, &u_x));
700*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetWorkspace(ds, &x, &basisReal, &basisDerReal, &testReal, &testDerReal));
701*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetWeakFormArrays(ds, NULL, NULL, &g0, &g1, &g2, &g3));
702*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTabulation(ds, &T));
703*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetFieldOffset(ds, fieldI, &offsetI));
704*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetFieldOffset(ds, fieldJ, &offsetJ));
705*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetConstants(ds, &numConstants, &constants));
7064bee2e38SMatthew G. Knepley   if (dsAux) {
707*9566063dSJacob Faibussowitsch     PetscCall(PetscDSGetNumFields(dsAux, &NfAux));
708*9566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalDimension(dsAux, &totDimAux));
709*9566063dSJacob Faibussowitsch     PetscCall(PetscDSGetComponentOffsets(dsAux, &aOff));
710*9566063dSJacob Faibussowitsch     PetscCall(PetscDSGetComponentDerivativeOffsets(dsAux, &aOff_x));
711*9566063dSJacob Faibussowitsch     PetscCall(PetscDSGetEvaluationArrays(dsAux, &a, NULL, &a_x));
712*9566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTabulation(dsAux, &TAux));
7132c71b3e2SJacob Faibussowitsch     PetscCheckFalse(T[0]->Np != TAux[0]->Np,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of tabulation points %D != %D number of auxiliary tabulation points", T[0]->Np, TAux[0]->Np);
71420cf1dd8SToby Isaac   }
71527f02ce8SMatthew G. Knepley   NcI = T[fieldI]->Nc;
71627f02ce8SMatthew G. Knepley   NcJ = T[fieldJ]->Nc;
7174bee2e38SMatthew G. Knepley   Np  = cgeom->numPoints;
7184bee2e38SMatthew G. Knepley   dE  = cgeom->dimEmbed;
7194bee2e38SMatthew G. Knepley   isAffine = cgeom->isAffine;
72027f02ce8SMatthew G. Knepley   /* Initialize here in case the function is not defined */
721*9566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(g0, NcI*NcJ));
722*9566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(g1, NcI*NcJ*dE));
723*9566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(g2, NcI*NcJ*dE));
724*9566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(g3, NcI*NcJ*dE*dE));
725*9566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights));
7262c71b3e2SJacob Faibussowitsch   PetscCheckFalse(qNc != 1,PETSC_COMM_SELF, PETSC_ERR_SUP, "Only supports scalar quadrature, not %D components", qNc);
7274bee2e38SMatthew G. Knepley   for (e = 0; e < Ne; ++e) {
7284bee2e38SMatthew G. Knepley     PetscFEGeom fegeom;
7294bee2e38SMatthew G. Knepley 
73027f02ce8SMatthew G. Knepley     fegeom.dim      = cgeom->dim;
73127f02ce8SMatthew G. Knepley     fegeom.dimEmbed = cgeom->dimEmbed;
7324bee2e38SMatthew G. Knepley     if (isAffine) {
7334bee2e38SMatthew G. Knepley       fegeom.v    = x;
7344bee2e38SMatthew G. Knepley       fegeom.xi   = cgeom->xi;
7357132c3f7SMatthew G. Knepley       fegeom.J    = &cgeom->J[e*Np*dE*dE];
7367132c3f7SMatthew G. Knepley       fegeom.invJ = &cgeom->invJ[e*Np*dE*dE];
7377132c3f7SMatthew G. Knepley       fegeom.detJ = &cgeom->detJ[e*Np];
7384bee2e38SMatthew G. Knepley     }
73920cf1dd8SToby Isaac     for (q = 0; q < Nq; ++q) {
74020cf1dd8SToby Isaac       PetscReal w;
7414bee2e38SMatthew G. Knepley       PetscInt  c;
74220cf1dd8SToby Isaac 
74320cf1dd8SToby Isaac       if (isAffine) {
7447132c3f7SMatthew G. Knepley         CoordinatesRefToReal(dE, dim, fegeom.xi, &cgeom->v[e*Np*dE], fegeom.J, &quadPoints[q*dim], x);
74520cf1dd8SToby Isaac       } else {
7464bee2e38SMatthew G. Knepley         fegeom.v    = &cgeom->v[(e*Np+q)*dE];
7474bee2e38SMatthew G. Knepley         fegeom.J    = &cgeom->J[(e*Np+q)*dE*dE];
7484bee2e38SMatthew G. Knepley         fegeom.invJ = &cgeom->invJ[(e*Np+q)*dE*dE];
7494bee2e38SMatthew G. Knepley         fegeom.detJ = &cgeom->detJ[e*Np+q];
75020cf1dd8SToby Isaac       }
751*9566063dSJacob Faibussowitsch       if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  quad point %" PetscInt_FMT " weight %g detJ %g\n", q, (double) quadWeights[q], (double) fegeom.detJ[0]));
7524bee2e38SMatthew G. Knepley       w = fegeom.detJ[0]*quadWeights[q];
753*9566063dSJacob Faibussowitsch       if (coefficients) PetscCall(PetscFEEvaluateFieldJets_Internal(ds, Nf, 0, q, T, &fegeom, &coefficients[cOffset], &coefficients_t[cOffset], u, u_x, u_t));
754*9566063dSJacob Faibussowitsch       if (dsAux)        PetscCall(PetscFEEvaluateFieldJets_Internal(dsAux, NfAux, 0, q, TAux, &fegeom, &coefficientsAux[cOffsetAux], NULL, a, a_x, NULL));
755ea672e62SMatthew G. Knepley       if (n0) {
756*9566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(g0, NcI*NcJ));
7576528b96dSMatthew G. Knepley         for (i = 0; i < n0; ++i) g0_func[i](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);
75820cf1dd8SToby Isaac         for (c = 0; c < NcI*NcJ; ++c) g0[c] *= w;
75920cf1dd8SToby Isaac       }
760ea672e62SMatthew G. Knepley       if (n1) {
761*9566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(g1, NcI*NcJ*dE));
7626528b96dSMatthew G. Knepley         for (i = 0; i < n1; ++i) g1_func[i](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);
7634bee2e38SMatthew G. Knepley         for (c = 0; c < NcI*NcJ*dim; ++c) g1[c] *= w;
76420cf1dd8SToby Isaac       }
765ea672e62SMatthew G. Knepley       if (n2) {
766*9566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(g2, NcI*NcJ*dE));
7676528b96dSMatthew G. Knepley         for (i = 0; i < n2; ++i) g2_func[i](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);
7684bee2e38SMatthew G. Knepley         for (c = 0; c < NcI*NcJ*dim; ++c) g2[c] *= w;
76920cf1dd8SToby Isaac       }
770ea672e62SMatthew G. Knepley       if (n3) {
771*9566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(g3, NcI*NcJ*dE*dE));
7726528b96dSMatthew G. Knepley         for (i = 0; i < n3; ++i) g3_func[i](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);
7734bee2e38SMatthew G. Knepley         for (c = 0; c < NcI*NcJ*dim*dim; ++c) g3[c] *= w;
77420cf1dd8SToby Isaac       }
77520cf1dd8SToby Isaac 
776*9566063dSJacob Faibussowitsch       PetscCall(PetscFEUpdateElementMat_Internal(feI, feJ, 0, q, T[fieldI], basisReal, basisDerReal, T[fieldJ], testReal, testDerReal, &fegeom, g0, g1, g2, g3, eOffset, totDim, offsetI, offsetJ, elemMat));
77720cf1dd8SToby Isaac     }
77820cf1dd8SToby Isaac     if (debug > 1) {
77920cf1dd8SToby Isaac       PetscInt fc, f, gc, g;
78020cf1dd8SToby Isaac 
781*9566063dSJacob Faibussowitsch       PetscCall(PetscPrintf(PETSC_COMM_SELF, "Element matrix for fields %d and %d\n", fieldI, fieldJ));
782ef0bb6c7SMatthew G. Knepley       for (fc = 0; fc < T[fieldI]->Nc; ++fc) {
783ef0bb6c7SMatthew G. Knepley         for (f = 0; f < T[fieldI]->Nb; ++f) {
784ef0bb6c7SMatthew G. Knepley           const PetscInt i = offsetI + f*T[fieldI]->Nc+fc;
785ef0bb6c7SMatthew G. Knepley           for (gc = 0; gc < T[fieldJ]->Nc; ++gc) {
786ef0bb6c7SMatthew G. Knepley             for (g = 0; g < T[fieldJ]->Nb; ++g) {
787ef0bb6c7SMatthew G. Knepley               const PetscInt j = offsetJ + g*T[fieldJ]->Nc+gc;
788*9566063dSJacob Faibussowitsch               PetscCall(PetscPrintf(PETSC_COMM_SELF, "    elemMat[%d,%d,%d,%d]: %g\n", f, fc, g, gc, PetscRealPart(elemMat[eOffset+i*totDim+j])));
78920cf1dd8SToby Isaac             }
79020cf1dd8SToby Isaac           }
791*9566063dSJacob Faibussowitsch           PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
79220cf1dd8SToby Isaac         }
79320cf1dd8SToby Isaac       }
79420cf1dd8SToby Isaac     }
79520cf1dd8SToby Isaac     cOffset    += totDim;
79620cf1dd8SToby Isaac     cOffsetAux += totDimAux;
79720cf1dd8SToby Isaac     eOffset    += PetscSqr(totDim);
79820cf1dd8SToby Isaac   }
79920cf1dd8SToby Isaac   PetscFunctionReturn(0);
80020cf1dd8SToby Isaac }
80120cf1dd8SToby Isaac 
80206ad1575SMatthew G. Knepley static PetscErrorCode PetscFEIntegrateBdJacobian_Basic(PetscDS ds, PetscWeakForm wf, PetscFormKey key, PetscInt Ne, PetscFEGeom *fgeom,
8034bee2e38SMatthew G. Knepley                                                        const PetscScalar coefficients[], const PetscScalar coefficients_t[], PetscDS dsAux, const PetscScalar coefficientsAux[], PetscReal t, PetscReal u_tshift, PetscScalar elemMat[])
80420cf1dd8SToby Isaac {
80520cf1dd8SToby Isaac   const PetscInt     debug      = 0;
8064bee2e38SMatthew G. Knepley   PetscFE            feI, feJ;
80745480ffeSMatthew G. Knepley   PetscBdPointJac   *g0_func, *g1_func, *g2_func, *g3_func;
80845480ffeSMatthew G. Knepley   PetscInt           n0,       n1,       n2,       n3, i;
80920cf1dd8SToby Isaac   PetscInt           cOffset    = 0; /* Offset into coefficients[] for element e */
81020cf1dd8SToby Isaac   PetscInt           cOffsetAux = 0; /* Offset into coefficientsAux[] for element e */
81120cf1dd8SToby Isaac   PetscInt           eOffset    = 0; /* Offset into elemMat[] for element e */
81220cf1dd8SToby Isaac   PetscInt           offsetI    = 0; /* Offset into an element vector for fieldI */
81320cf1dd8SToby Isaac   PetscInt           offsetJ    = 0; /* Offset into an element vector for fieldJ */
81420cf1dd8SToby Isaac   PetscQuadrature    quad;
815ef0bb6c7SMatthew G. Knepley   PetscTabulation   *T, *TAux = NULL;
8164bee2e38SMatthew G. Knepley   PetscScalar       *g0, *g1, *g2, *g3, *u, *u_t = NULL, *u_x, *a, *a_x, *basisReal, *basisDerReal, *testReal, *testDerReal;
81720cf1dd8SToby Isaac   const PetscScalar *constants;
81820cf1dd8SToby Isaac   PetscReal         *x;
819ef0bb6c7SMatthew G. Knepley   PetscInt          *uOff, *uOff_x, *aOff = NULL, *aOff_x = NULL;
820ef0bb6c7SMatthew G. Knepley   PetscInt           NcI = 0, NcJ = 0;
82145480ffeSMatthew G. Knepley   PetscInt           dim, numConstants, Nf, fieldI, fieldJ, NfAux = 0, totDim, totDimAux = 0, e;
82220cf1dd8SToby Isaac   PetscBool          isAffine;
82320cf1dd8SToby Isaac   const PetscReal   *quadPoints, *quadWeights;
82420cf1dd8SToby Isaac   PetscInt           qNc, Nq, q, Np, dE;
82520cf1dd8SToby Isaac 
82620cf1dd8SToby Isaac   PetscFunctionBegin;
827*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &Nf));
82845480ffeSMatthew G. Knepley   fieldI = key.field / Nf;
82945480ffeSMatthew G. Knepley   fieldJ = key.field % Nf;
830*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetDiscretization(ds, fieldI, (PetscObject *) &feI));
831*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetDiscretization(ds, fieldJ, (PetscObject *) &feJ));
832*9566063dSJacob Faibussowitsch   PetscCall(PetscFEGetSpatialDimension(feI, &dim));
833*9566063dSJacob Faibussowitsch   PetscCall(PetscFEGetFaceQuadrature(feI, &quad));
834*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(ds, &totDim));
835*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponentOffsets(ds, &uOff));
836*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponentDerivativeOffsets(ds, &uOff_x));
837*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetFieldOffset(ds, fieldI, &offsetI));
838*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetFieldOffset(ds, fieldJ, &offsetJ));
839*9566063dSJacob Faibussowitsch   PetscCall(PetscWeakFormGetBdJacobian(wf, key.label, key.value, fieldI, fieldJ, key.part, &n0, &g0_func, &n1, &g1_func, &n2, &g2_func, &n3, &g3_func));
84045480ffeSMatthew G. Knepley   if (!n0 && !n1 && !n2 && !n3) PetscFunctionReturn(0);
841*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetEvaluationArrays(ds, &u, coefficients_t ? &u_t : NULL, &u_x));
842*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetWorkspace(ds, &x, &basisReal, &basisDerReal, &testReal, &testDerReal));
843*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetWeakFormArrays(ds, NULL, NULL, &g0, &g1, &g2, &g3));
844*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetFaceTabulation(ds, &T));
845*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetConstants(ds, &numConstants, &constants));
8464bee2e38SMatthew G. Knepley   if (dsAux) {
847*9566063dSJacob Faibussowitsch     PetscCall(PetscDSGetNumFields(dsAux, &NfAux));
848*9566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalDimension(dsAux, &totDimAux));
849*9566063dSJacob Faibussowitsch     PetscCall(PetscDSGetComponentOffsets(dsAux, &aOff));
850*9566063dSJacob Faibussowitsch     PetscCall(PetscDSGetComponentDerivativeOffsets(dsAux, &aOff_x));
851*9566063dSJacob Faibussowitsch     PetscCall(PetscDSGetEvaluationArrays(dsAux, &a, NULL, &a_x));
852*9566063dSJacob Faibussowitsch     PetscCall(PetscDSGetFaceTabulation(dsAux, &TAux));
85320cf1dd8SToby Isaac   }
854ef0bb6c7SMatthew G. Knepley   NcI = T[fieldI]->Nc, NcJ = T[fieldJ]->Nc;
85520cf1dd8SToby Isaac   Np = fgeom->numPoints;
85620cf1dd8SToby Isaac   dE = fgeom->dimEmbed;
85720cf1dd8SToby Isaac   isAffine = fgeom->isAffine;
85827f02ce8SMatthew G. Knepley   /* Initialize here in case the function is not defined */
859*9566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(g0, NcI*NcJ));
860*9566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(g1, NcI*NcJ*dE));
861*9566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(g2, NcI*NcJ*dE));
862*9566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(g3, NcI*NcJ*dE*dE));
863*9566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights));
8642c71b3e2SJacob Faibussowitsch   PetscCheckFalse(qNc != 1,PETSC_COMM_SELF, PETSC_ERR_SUP, "Only supports scalar quadrature, not %D components", qNc);
86520cf1dd8SToby Isaac   for (e = 0; e < Ne; ++e) {
8669f209ee4SMatthew G. Knepley     PetscFEGeom    fegeom, cgeom;
86720cf1dd8SToby Isaac     const PetscInt face = fgeom->face[e][0];
868ea78f98cSLisandro Dalcin     fegeom.n = NULL;
869ea78f98cSLisandro Dalcin     fegeom.v = NULL;
870ea78f98cSLisandro Dalcin     fegeom.J = NULL;
871ea78f98cSLisandro Dalcin     fegeom.detJ = NULL;
87227f02ce8SMatthew G. Knepley     fegeom.dim      = fgeom->dim;
87327f02ce8SMatthew G. Knepley     fegeom.dimEmbed = fgeom->dimEmbed;
87427f02ce8SMatthew G. Knepley     cgeom.dim       = fgeom->dim;
87527f02ce8SMatthew G. Knepley     cgeom.dimEmbed  = fgeom->dimEmbed;
8764bee2e38SMatthew G. Knepley     if (isAffine) {
8774bee2e38SMatthew G. Knepley       fegeom.v    = x;
8784bee2e38SMatthew G. Knepley       fegeom.xi   = fgeom->xi;
8797132c3f7SMatthew G. Knepley       fegeom.J    = &fgeom->J[e*Np*dE*dE];
8807132c3f7SMatthew G. Knepley       fegeom.invJ = &fgeom->invJ[e*Np*dE*dE];
8817132c3f7SMatthew G. Knepley       fegeom.detJ = &fgeom->detJ[e*Np];
8827132c3f7SMatthew G. Knepley       fegeom.n    = &fgeom->n[e*Np*dE];
8839f209ee4SMatthew G. Knepley 
8847132c3f7SMatthew G. Knepley       cgeom.J     = &fgeom->suppJ[0][e*Np*dE*dE];
8857132c3f7SMatthew G. Knepley       cgeom.invJ  = &fgeom->suppInvJ[0][e*Np*dE*dE];
8867132c3f7SMatthew G. Knepley       cgeom.detJ  = &fgeom->suppDetJ[0][e*Np];
8874bee2e38SMatthew G. Knepley     }
88820cf1dd8SToby Isaac     for (q = 0; q < Nq; ++q) {
88920cf1dd8SToby Isaac       PetscReal w;
8904bee2e38SMatthew G. Knepley       PetscInt  c;
89120cf1dd8SToby Isaac 
892*9566063dSJacob Faibussowitsch       if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  quad point %d\n", q));
89320cf1dd8SToby Isaac       if (isAffine) {
8947132c3f7SMatthew G. Knepley         CoordinatesRefToReal(dE, dim-1, fegeom.xi, &fgeom->v[e*Np*dE], fegeom.J, &quadPoints[q*(dim-1)], x);
89520cf1dd8SToby Isaac       } else {
8963fe841f2SMatthew G. Knepley         fegeom.v    = &fgeom->v[(e*Np+q)*dE];
8979f209ee4SMatthew G. Knepley         fegeom.J    = &fgeom->J[(e*Np+q)*dE*dE];
8989f209ee4SMatthew G. Knepley         fegeom.invJ = &fgeom->invJ[(e*Np+q)*dE*dE];
8994bee2e38SMatthew G. Knepley         fegeom.detJ = &fgeom->detJ[e*Np+q];
9004bee2e38SMatthew G. Knepley         fegeom.n    = &fgeom->n[(e*Np+q)*dE];
9019f209ee4SMatthew G. Knepley 
9029f209ee4SMatthew G. Knepley         cgeom.J     = &fgeom->suppJ[0][(e*Np+q)*dE*dE];
9039f209ee4SMatthew G. Knepley         cgeom.invJ  = &fgeom->suppInvJ[0][(e*Np+q)*dE*dE];
9049f209ee4SMatthew G. Knepley         cgeom.detJ  = &fgeom->suppDetJ[0][e*Np+q];
90520cf1dd8SToby Isaac       }
9064bee2e38SMatthew G. Knepley       w = fegeom.detJ[0]*quadWeights[q];
907*9566063dSJacob Faibussowitsch       if (coefficients) PetscCall(PetscFEEvaluateFieldJets_Internal(ds, Nf, face, q, T, &cgeom, &coefficients[cOffset], &coefficients_t[cOffset], u, u_x, u_t));
908*9566063dSJacob Faibussowitsch       if (dsAux)        PetscCall(PetscFEEvaluateFieldJets_Internal(dsAux, NfAux, face, q, TAux, &cgeom, &coefficientsAux[cOffsetAux], NULL, a, a_x, NULL));
909ea672e62SMatthew G. Knepley       if (n0) {
910*9566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(g0, NcI*NcJ));
91145480ffeSMatthew G. Knepley         for (i = 0; i < n0; ++i) g0_func[i](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);
91220cf1dd8SToby Isaac         for (c = 0; c < NcI*NcJ; ++c) g0[c] *= w;
91320cf1dd8SToby Isaac       }
914ea672e62SMatthew G. Knepley       if (n1) {
915*9566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(g1, NcI*NcJ*dE));
91645480ffeSMatthew G. Knepley         for (i = 0; i < n1; ++i) g1_func[i](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);
9174bee2e38SMatthew G. Knepley         for (c = 0; c < NcI*NcJ*dim; ++c) g1[c] *= w;
91820cf1dd8SToby Isaac       }
919ea672e62SMatthew G. Knepley       if (n2) {
920*9566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(g2, NcI*NcJ*dE));
92145480ffeSMatthew G. Knepley         for (i = 0; i < n2; ++i) g2_func[i](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);
9224bee2e38SMatthew G. Knepley         for (c = 0; c < NcI*NcJ*dim; ++c) g2[c] *= w;
92320cf1dd8SToby Isaac       }
924ea672e62SMatthew G. Knepley       if (n3) {
925*9566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(g3, NcI*NcJ*dE*dE));
92645480ffeSMatthew G. Knepley         for (i = 0; i < n3; ++i) g3_func[i](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);
9274bee2e38SMatthew G. Knepley         for (c = 0; c < NcI*NcJ*dim*dim; ++c) g3[c] *= w;
92820cf1dd8SToby Isaac       }
92920cf1dd8SToby Isaac 
930*9566063dSJacob Faibussowitsch       PetscCall(PetscFEUpdateElementMat_Internal(feI, feJ, face, q, T[fieldI], basisReal, basisDerReal, T[fieldJ], testReal, testDerReal, &cgeom, g0, g1, g2, g3, eOffset, totDim, offsetI, offsetJ, elemMat));
93120cf1dd8SToby Isaac     }
93220cf1dd8SToby Isaac     if (debug > 1) {
93320cf1dd8SToby Isaac       PetscInt fc, f, gc, g;
93420cf1dd8SToby Isaac 
935*9566063dSJacob Faibussowitsch       PetscCall(PetscPrintf(PETSC_COMM_SELF, "Element matrix for fields %d and %d\n", fieldI, fieldJ));
936ef0bb6c7SMatthew G. Knepley       for (fc = 0; fc < T[fieldI]->Nc; ++fc) {
937ef0bb6c7SMatthew G. Knepley         for (f = 0; f < T[fieldI]->Nb; ++f) {
938ef0bb6c7SMatthew G. Knepley           const PetscInt i = offsetI + f*T[fieldI]->Nc+fc;
939ef0bb6c7SMatthew G. Knepley           for (gc = 0; gc < T[fieldJ]->Nc; ++gc) {
940ef0bb6c7SMatthew G. Knepley             for (g = 0; g < T[fieldJ]->Nb; ++g) {
941ef0bb6c7SMatthew G. Knepley               const PetscInt j = offsetJ + g*T[fieldJ]->Nc+gc;
942*9566063dSJacob Faibussowitsch               PetscCall(PetscPrintf(PETSC_COMM_SELF, "    elemMat[%d,%d,%d,%d]: %g\n", f, fc, g, gc, PetscRealPart(elemMat[eOffset+i*totDim+j])));
94320cf1dd8SToby Isaac             }
94420cf1dd8SToby Isaac           }
945*9566063dSJacob Faibussowitsch           PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
94620cf1dd8SToby Isaac         }
94720cf1dd8SToby Isaac       }
94820cf1dd8SToby Isaac     }
94920cf1dd8SToby Isaac     cOffset    += totDim;
95020cf1dd8SToby Isaac     cOffsetAux += totDimAux;
95120cf1dd8SToby Isaac     eOffset    += PetscSqr(totDim);
95220cf1dd8SToby Isaac   }
95320cf1dd8SToby Isaac   PetscFunctionReturn(0);
95420cf1dd8SToby Isaac }
95520cf1dd8SToby Isaac 
9565fedec97SMatthew G. Knepley PetscErrorCode PetscFEIntegrateHybridJacobian_Basic(PetscDS ds, PetscFEJacobianType jtype, PetscFormKey key, PetscInt s, PetscInt Ne, PetscFEGeom *fgeom,
95727f02ce8SMatthew G. Knepley                                               const PetscScalar coefficients[], const PetscScalar coefficients_t[], PetscDS dsAux, const PetscScalar coefficientsAux[], PetscReal t, PetscReal u_tshift, PetscScalar elemMat[])
95827f02ce8SMatthew G. Knepley {
95927f02ce8SMatthew G. Knepley   const PetscInt     debug      = 0;
96027f02ce8SMatthew G. Knepley   PetscFE            feI, feJ;
961148442b3SMatthew G. Knepley   PetscWeakForm      wf;
962148442b3SMatthew G. Knepley   PetscBdPointJac   *g0_func, *g1_func, *g2_func, *g3_func;
963148442b3SMatthew G. Knepley   PetscInt           n0,       n1,       n2,       n3, i;
96427f02ce8SMatthew G. Knepley   PetscInt           cOffset    = 0; /* Offset into coefficients[] for element e */
96527f02ce8SMatthew G. Knepley   PetscInt           cOffsetAux = 0; /* Offset into coefficientsAux[] for element e */
96627f02ce8SMatthew G. Knepley   PetscInt           eOffset    = 0; /* Offset into elemMat[] for element e */
96727f02ce8SMatthew G. Knepley   PetscInt           offsetI    = 0; /* Offset into an element vector for fieldI */
96827f02ce8SMatthew G. Knepley   PetscInt           offsetJ    = 0; /* Offset into an element vector for fieldJ */
969665f567fSMatthew G. Knepley   PetscQuadrature    quad;
970665f567fSMatthew G. Knepley   PetscTabulation   *T, *TAux = NULL;
97127f02ce8SMatthew G. Knepley   PetscScalar       *g0, *g1, *g2, *g3, *u, *u_t = NULL, *u_x, *a, *a_x, *basisReal, *basisDerReal, *testReal, *testDerReal;
97227f02ce8SMatthew G. Knepley   const PetscScalar *constants;
97327f02ce8SMatthew G. Knepley   PetscReal         *x;
974665f567fSMatthew G. Knepley   PetscInt          *uOff, *uOff_x, *aOff = NULL, *aOff_x = NULL;
975665f567fSMatthew G. Knepley   PetscInt           NcI = 0, NcJ = 0, NcS, NcT;
97645480ffeSMatthew G. Knepley   PetscInt           dim, dimAux, numConstants, Nf, fieldI, fieldJ, NfAux = 0, totDim, totDimAux = 0, e;
977665f567fSMatthew G. Knepley   PetscBool          isCohesiveFieldI, isCohesiveFieldJ, isAffine, auxOnBd = PETSC_FALSE;
97827f02ce8SMatthew G. Knepley   const PetscReal   *quadPoints, *quadWeights;
97927f02ce8SMatthew G. Knepley   PetscInt           qNc, Nq, q, Np, dE;
98027f02ce8SMatthew G. Knepley 
98127f02ce8SMatthew G. Knepley   PetscFunctionBegin;
982*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &Nf));
98345480ffeSMatthew G. Knepley   fieldI = key.field / Nf;
98445480ffeSMatthew G. Knepley   fieldJ = key.field % Nf;
98527f02ce8SMatthew G. Knepley   /* Hybrid discretization is posed directly on faces */
986*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetDiscretization(ds, fieldI, (PetscObject *) &feI));
987*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetDiscretization(ds, fieldJ, (PetscObject *) &feJ));
988*9566063dSJacob Faibussowitsch   PetscCall(PetscFEGetSpatialDimension(feI, &dim));
989*9566063dSJacob Faibussowitsch   PetscCall(PetscFEGetQuadrature(feI, &quad));
990*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(ds, &totDim));
991*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponentOffsetsCohesive(ds, s, &uOff));
992*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponentDerivativeOffsetsCohesive(ds, s, &uOff_x));
993*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetWeakForm(ds, &wf));
99427f02ce8SMatthew G. Knepley   switch(jtype) {
995*9566063dSJacob Faibussowitsch   case PETSCFE_JACOBIAN_PRE: PetscCall(PetscWeakFormGetBdJacobianPreconditioner(wf, key.label, key.value, fieldI, fieldJ, key.part, &n0, &g0_func, &n1, &g1_func, &n2, &g2_func, &n3, &g3_func));break;
996*9566063dSJacob Faibussowitsch   case PETSCFE_JACOBIAN:     PetscCall(PetscWeakFormGetBdJacobian(wf, key.label, key.value, fieldI, fieldJ, key.part, &n0, &g0_func, &n1, &g1_func, &n2, &g2_func, &n3, &g3_func));break;
997665f567fSMatthew G. Knepley   case PETSCFE_JACOBIAN_DYN: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No boundary hybrid Jacobians :)");
99827f02ce8SMatthew G. Knepley   }
999148442b3SMatthew G. Knepley   if (!n0 && !n1 && !n2 && !n3) PetscFunctionReturn(0);
1000*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetEvaluationArrays(ds, &u, coefficients_t ? &u_t : NULL, &u_x));
1001*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetWorkspace(ds, &x, &basisReal, &basisDerReal, &testReal, &testDerReal));
1002*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetWeakFormArrays(ds, NULL, NULL, &g0, &g1, &g2, &g3));
1003*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTabulation(ds, &T));
1004*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetFieldOffsetCohesive(ds, fieldI, &offsetI));
1005*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetFieldOffsetCohesive(ds, fieldJ, &offsetJ));
1006*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetConstants(ds, &numConstants, &constants));
100727f02ce8SMatthew G. Knepley   if (dsAux) {
1008*9566063dSJacob Faibussowitsch     PetscCall(PetscDSGetSpatialDimension(dsAux, &dimAux));
1009*9566063dSJacob Faibussowitsch     PetscCall(PetscDSGetNumFields(dsAux, &NfAux));
1010*9566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalDimension(dsAux, &totDimAux));
1011*9566063dSJacob Faibussowitsch     PetscCall(PetscDSGetComponentOffsets(dsAux, &aOff));
1012*9566063dSJacob Faibussowitsch     PetscCall(PetscDSGetComponentDerivativeOffsets(dsAux, &aOff_x));
1013*9566063dSJacob Faibussowitsch     PetscCall(PetscDSGetEvaluationArrays(dsAux, &a, NULL, &a_x));
101401907d53SMatthew G. Knepley     auxOnBd = dimAux == dim ? PETSC_TRUE : PETSC_FALSE;
1015*9566063dSJacob Faibussowitsch     if (auxOnBd) PetscCall(PetscDSGetTabulation(dsAux, &TAux));
1016*9566063dSJacob Faibussowitsch     else         PetscCall(PetscDSGetFaceTabulation(dsAux, &TAux));
10172c71b3e2SJacob Faibussowitsch     PetscCheckFalse(T[0]->Np != TAux[0]->Np,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of tabulation points %D != %D number of auxiliary tabulation points", T[0]->Np, TAux[0]->Np);
101827f02ce8SMatthew G. Knepley   }
1019*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetCohesive(ds, fieldI, &isCohesiveFieldI));
1020*9566063dSJacob Faibussowitsch   PetscCall(PetscDSGetCohesive(ds, fieldJ, &isCohesiveFieldJ));
1021665f567fSMatthew G. Knepley   NcI = T[fieldI]->Nc;
1022665f567fSMatthew G. Knepley   NcJ = T[fieldJ]->Nc;
102327f02ce8SMatthew G. Knepley   NcS = isCohesiveFieldI ? NcI : 2*NcI;
102427f02ce8SMatthew G. Knepley   NcT = isCohesiveFieldJ ? NcJ : 2*NcJ;
102527f02ce8SMatthew G. Knepley   Np = fgeom->numPoints;
102627f02ce8SMatthew G. Knepley   dE = fgeom->dimEmbed;
102727f02ce8SMatthew G. Knepley   isAffine = fgeom->isAffine;
1028*9566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(g0, NcS*NcT));
1029*9566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(g1, NcS*NcT*dE));
1030*9566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(g2, NcS*NcT*dE));
1031*9566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(g3, NcS*NcT*dE*dE));
1032*9566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights));
10332c71b3e2SJacob Faibussowitsch   PetscCheckFalse(qNc != 1,PETSC_COMM_SELF, PETSC_ERR_SUP, "Only supports scalar quadrature, not %D components", qNc);
103427f02ce8SMatthew G. Knepley   for (e = 0; e < Ne; ++e) {
103527f02ce8SMatthew G. Knepley     PetscFEGeom    fegeom;
103627f02ce8SMatthew G. Knepley     const PetscInt face = fgeom->face[e][0];
103727f02ce8SMatthew G. Knepley 
103827f02ce8SMatthew G. Knepley     fegeom.dim      = fgeom->dim;
103927f02ce8SMatthew G. Knepley     fegeom.dimEmbed = fgeom->dimEmbed;
104027f02ce8SMatthew G. Knepley     if (isAffine) {
104127f02ce8SMatthew G. Knepley       fegeom.v    = x;
104227f02ce8SMatthew G. Knepley       fegeom.xi   = fgeom->xi;
104327f02ce8SMatthew G. Knepley       fegeom.J    = &fgeom->J[e*dE*dE];
104427f02ce8SMatthew G. Knepley       fegeom.invJ = &fgeom->invJ[e*dE*dE];
104527f02ce8SMatthew G. Knepley       fegeom.detJ = &fgeom->detJ[e];
104627f02ce8SMatthew G. Knepley       fegeom.n    = &fgeom->n[e*dE];
104727f02ce8SMatthew G. Knepley     }
104827f02ce8SMatthew G. Knepley     for (q = 0; q < Nq; ++q) {
104927f02ce8SMatthew G. Knepley       PetscReal w;
105027f02ce8SMatthew G. Knepley       PetscInt  c;
105127f02ce8SMatthew G. Knepley 
105227f02ce8SMatthew G. Knepley       if (isAffine) {
105327f02ce8SMatthew G. Knepley         /* TODO Is it correct to have 'dim' here, or should it be 'dim-1'? */
105427f02ce8SMatthew G. Knepley         CoordinatesRefToReal(dE, dim, fegeom.xi, &fgeom->v[e*dE], fegeom.J, &quadPoints[q*dim], x);
105527f02ce8SMatthew G. Knepley       } else {
105627f02ce8SMatthew G. Knepley         fegeom.v    = &fegeom.v[(e*Np+q)*dE];
105727f02ce8SMatthew G. Knepley         fegeom.J    = &fgeom->J[(e*Np+q)*dE*dE];
105827f02ce8SMatthew G. Knepley         fegeom.invJ = &fgeom->invJ[(e*Np+q)*dE*dE];
105927f02ce8SMatthew G. Knepley         fegeom.detJ = &fgeom->detJ[e*Np+q];
106027f02ce8SMatthew G. Knepley         fegeom.n    = &fgeom->n[(e*Np+q)*dE];
106127f02ce8SMatthew G. Knepley       }
106227f02ce8SMatthew G. Knepley       w = fegeom.detJ[0]*quadWeights[q];
106327f02ce8SMatthew G. Knepley       if (debug > 1 && q < Np) {
1064*9566063dSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "  detJ: %g\n", fegeom.detJ[0]));
106527f02ce8SMatthew G. Knepley #if !defined(PETSC_USE_COMPLEX)
1066*9566063dSJacob Faibussowitsch         PetscCall(DMPrintCellMatrix(e, "invJ", dim, dim, fegeom.invJ));
106727f02ce8SMatthew G. Knepley #endif
106827f02ce8SMatthew G. Knepley       }
1069*9566063dSJacob Faibussowitsch       if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  quad point %d\n", q));
1070*9566063dSJacob Faibussowitsch       if (coefficients) PetscCall(PetscFEEvaluateFieldJets_Hybrid_Internal(ds, Nf, 0, q, T, &fegeom, &coefficients[cOffset], &coefficients_t[cOffset], u, u_x, u_t));
1071*9566063dSJacob Faibussowitsch       if (dsAux) PetscCall(PetscFEEvaluateFieldJets_Internal(dsAux, NfAux, 0, auxOnBd ? q : face*Nq+q, TAux, &fegeom, &coefficientsAux[cOffsetAux], NULL, a, a_x, NULL));
1072ea672e62SMatthew G. Knepley       if (n0) {
1073*9566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(g0, NcS*NcT));
1074148442b3SMatthew G. Knepley         for (i = 0; i < n0; ++i) g0_func[i](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);
107527f02ce8SMatthew G. Knepley         for (c = 0; c < NcS*NcT; ++c) g0[c] *= w;
107627f02ce8SMatthew G. Knepley       }
1077ea672e62SMatthew G. Knepley       if (n1) {
1078*9566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(g1, NcS*NcT*dE));
1079148442b3SMatthew G. Knepley         for (i = 0; i < n1; ++i) g1_func[i](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);
108027f02ce8SMatthew G. Knepley         for (c = 0; c < NcS*NcT*dE; ++c) g1[c] *= w;
108127f02ce8SMatthew G. Knepley       }
1082ea672e62SMatthew G. Knepley       if (n2) {
1083*9566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(g2, NcS*NcT*dE));
1084148442b3SMatthew G. Knepley         for (i = 0; i < n2; ++i) g2_func[i](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);
108527f02ce8SMatthew G. Knepley         for (c = 0; c < NcS*NcT*dE; ++c) g2[c] *= w;
108627f02ce8SMatthew G. Knepley       }
1087ea672e62SMatthew G. Knepley       if (n3) {
1088*9566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(g3, NcS*NcT*dE*dE));
1089148442b3SMatthew G. Knepley         for (i = 0; i < n3; ++i) g3_func[i](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);
109027f02ce8SMatthew G. Knepley         for (c = 0; c < NcS*NcT*dE*dE; ++c) g3[c] *= w;
109127f02ce8SMatthew G. Knepley       }
109227f02ce8SMatthew G. Knepley 
10935fedec97SMatthew G. Knepley       if (isCohesiveFieldI) {
10945fedec97SMatthew G. Knepley         if (isCohesiveFieldJ) {
1095*9566063dSJacob Faibussowitsch           PetscCall(PetscFEUpdateElementMat_Internal(feI, feJ, 0, q, T[fieldI], basisReal, basisDerReal, T[fieldJ], testReal, testDerReal, &fegeom, g0, g1, g2, g3, eOffset, totDim, offsetI, offsetJ, elemMat));
109627f02ce8SMatthew G. Knepley         } else {
1097*9566063dSJacob Faibussowitsch           PetscCall(PetscFEUpdateElementMat_Hybrid_Internal(feI, isCohesiveFieldI, feJ, isCohesiveFieldJ, 0, 0, q, T[fieldI], basisReal, basisDerReal, T[fieldJ], testReal, testDerReal, &fegeom, g0, g1, g2, g3, eOffset, totDim, offsetI, offsetJ, elemMat));
1098*9566063dSJacob Faibussowitsch           PetscCall(PetscFEUpdateElementMat_Hybrid_Internal(feI, isCohesiveFieldI, feJ, isCohesiveFieldJ, 0, 1, q, T[fieldI], basisReal, basisDerReal, T[fieldJ], testReal, testDerReal, &fegeom, &g0[NcI*NcJ], &g1[NcI*NcJ*dim], &g2[NcI*NcJ*dim], &g3[NcI*NcJ*dim*dim], eOffset, totDim, offsetI, offsetJ, elemMat));
10995fedec97SMatthew G. Knepley         }
11005fedec97SMatthew G. Knepley       } else {
1101*9566063dSJacob Faibussowitsch         PetscCall(PetscFEUpdateElementMat_Hybrid_Internal(feI, isCohesiveFieldI, feJ, isCohesiveFieldJ, 0, s, q, T[fieldI], basisReal, basisDerReal, T[fieldJ], testReal, testDerReal, &fegeom, g0, g1, g2, g3, eOffset, totDim, offsetI, offsetJ, elemMat));
110227f02ce8SMatthew G. Knepley       }
110327f02ce8SMatthew G. Knepley     }
110427f02ce8SMatthew G. Knepley     if (debug > 1) {
110527f02ce8SMatthew G. Knepley       PetscInt fc, f, gc, g;
110627f02ce8SMatthew G. Knepley 
1107*9566063dSJacob Faibussowitsch       PetscCall(PetscPrintf(PETSC_COMM_SELF, "Element matrix for fields %d and %d\n", fieldI, fieldJ));
110827f02ce8SMatthew G. Knepley       for (fc = 0; fc < NcI; ++fc) {
1109665f567fSMatthew G. Knepley         for (f = 0; f < T[fieldI]->Nb; ++f) {
111027f02ce8SMatthew G. Knepley           const PetscInt i = offsetI + f*NcI+fc;
111127f02ce8SMatthew G. Knepley           for (gc = 0; gc < NcJ; ++gc) {
1112665f567fSMatthew G. Knepley             for (g = 0; g < T[fieldJ]->Nb; ++g) {
111327f02ce8SMatthew G. Knepley               const PetscInt j = offsetJ + g*NcJ+gc;
1114*9566063dSJacob Faibussowitsch               PetscCall(PetscPrintf(PETSC_COMM_SELF, "    elemMat[%d,%d,%d,%d]: %g\n", f, fc, g, gc, PetscRealPart(elemMat[eOffset+i*totDim+j])));
111527f02ce8SMatthew G. Knepley             }
111627f02ce8SMatthew G. Knepley           }
1117*9566063dSJacob Faibussowitsch           PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
111827f02ce8SMatthew G. Knepley         }
111927f02ce8SMatthew G. Knepley       }
112027f02ce8SMatthew G. Knepley     }
112127f02ce8SMatthew G. Knepley     cOffset    += totDim;
112227f02ce8SMatthew G. Knepley     cOffsetAux += totDimAux;
112327f02ce8SMatthew G. Knepley     eOffset    += PetscSqr(totDim);
112427f02ce8SMatthew G. Knepley   }
112527f02ce8SMatthew G. Knepley   PetscFunctionReturn(0);
112627f02ce8SMatthew G. Knepley }
112727f02ce8SMatthew G. Knepley 
11282b99622eSMatthew G. Knepley static PetscErrorCode PetscFEInitialize_Basic(PetscFE fem)
112920cf1dd8SToby Isaac {
113020cf1dd8SToby Isaac   PetscFunctionBegin;
113120cf1dd8SToby Isaac   fem->ops->setfromoptions          = NULL;
113220cf1dd8SToby Isaac   fem->ops->setup                   = PetscFESetUp_Basic;
113320cf1dd8SToby Isaac   fem->ops->view                    = PetscFEView_Basic;
113420cf1dd8SToby Isaac   fem->ops->destroy                 = PetscFEDestroy_Basic;
113520cf1dd8SToby Isaac   fem->ops->getdimension            = PetscFEGetDimension_Basic;
1136ef0bb6c7SMatthew G. Knepley   fem->ops->createtabulation        = PetscFECreateTabulation_Basic;
113720cf1dd8SToby Isaac   fem->ops->integrate               = PetscFEIntegrate_Basic;
1138afe6d6adSToby Isaac   fem->ops->integratebd             = PetscFEIntegrateBd_Basic;
113920cf1dd8SToby Isaac   fem->ops->integrateresidual       = PetscFEIntegrateResidual_Basic;
114020cf1dd8SToby Isaac   fem->ops->integratebdresidual     = PetscFEIntegrateBdResidual_Basic;
114127f02ce8SMatthew G. Knepley   fem->ops->integratehybridresidual = PetscFEIntegrateHybridResidual_Basic;
114220cf1dd8SToby Isaac   fem->ops->integratejacobianaction = NULL/* PetscFEIntegrateJacobianAction_Basic */;
114320cf1dd8SToby Isaac   fem->ops->integratejacobian       = PetscFEIntegrateJacobian_Basic;
114420cf1dd8SToby Isaac   fem->ops->integratebdjacobian     = PetscFEIntegrateBdJacobian_Basic;
114527f02ce8SMatthew G. Knepley   fem->ops->integratehybridjacobian = PetscFEIntegrateHybridJacobian_Basic;
114620cf1dd8SToby Isaac   PetscFunctionReturn(0);
114720cf1dd8SToby Isaac }
114820cf1dd8SToby Isaac 
114920cf1dd8SToby Isaac /*MC
115020cf1dd8SToby Isaac   PETSCFEBASIC = "basic" - A PetscFE object that integrates with basic tiling and no vectorization
115120cf1dd8SToby Isaac 
115220cf1dd8SToby Isaac   Level: intermediate
115320cf1dd8SToby Isaac 
115420cf1dd8SToby Isaac .seealso: PetscFEType, PetscFECreate(), PetscFESetType()
115520cf1dd8SToby Isaac M*/
115620cf1dd8SToby Isaac 
115720cf1dd8SToby Isaac PETSC_EXTERN PetscErrorCode PetscFECreate_Basic(PetscFE fem)
115820cf1dd8SToby Isaac {
115920cf1dd8SToby Isaac   PetscFE_Basic *b;
116020cf1dd8SToby Isaac 
116120cf1dd8SToby Isaac   PetscFunctionBegin;
116220cf1dd8SToby Isaac   PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1);
1163*9566063dSJacob Faibussowitsch   PetscCall(PetscNewLog(fem,&b));
116420cf1dd8SToby Isaac   fem->data = b;
116520cf1dd8SToby Isaac 
1166*9566063dSJacob Faibussowitsch   PetscCall(PetscFEInitialize_Basic(fem));
116720cf1dd8SToby Isaac   PetscFunctionReturn(0);
116820cf1dd8SToby Isaac }
1169