xref: /petsc/src/dm/dt/fe/impls/basic/febasic.c (revision dce8aeba1c9b69b19f651c53d8a6b674bd7e9cbd)
120cf1dd8SToby Isaac #include <petsc/private/petscfeimpl.h> /*I "petscfe.h" I*/
220cf1dd8SToby Isaac #include <petscblaslapack.h>
320cf1dd8SToby Isaac 
4d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscFEDestroy_Basic(PetscFE fem)
5d71ae5a4SJacob Faibussowitsch {
620cf1dd8SToby Isaac   PetscFE_Basic *b = (PetscFE_Basic *)fem->data;
720cf1dd8SToby Isaac 
820cf1dd8SToby Isaac   PetscFunctionBegin;
99566063dSJacob Faibussowitsch   PetscCall(PetscFree(b));
1020cf1dd8SToby Isaac   PetscFunctionReturn(0);
1120cf1dd8SToby Isaac }
1220cf1dd8SToby Isaac 
13d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscFEView_Basic_Ascii(PetscFE fe, PetscViewer v)
14d71ae5a4SJacob Faibussowitsch {
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;
219566063dSJacob Faibussowitsch   PetscCall(PetscFEGetSpatialDimension(fe, &dim));
229566063dSJacob Faibussowitsch   PetscCall(PetscFEGetNumComponents(fe, &Nc));
239566063dSJacob Faibussowitsch   PetscCall(PetscFEGetBasisSpace(fe, &basis));
249566063dSJacob Faibussowitsch   PetscCall(PetscFEGetDualSpace(fe, &dual));
259566063dSJacob Faibussowitsch   PetscCall(PetscFEGetQuadrature(fe, &quad));
269566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPushTab(v));
2763a3b9bcSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPrintf(v, "Basic Finite Element in %" PetscInt_FMT " dimensions with %" PetscInt_FMT " components\n", dim, Nc));
289566063dSJacob Faibussowitsch   if (basis) PetscCall(PetscSpaceView(basis, v));
299566063dSJacob Faibussowitsch   if (dual) PetscCall(PetscDualSpaceView(dual, v));
309566063dSJacob Faibussowitsch   if (quad) PetscCall(PetscQuadratureView(quad, v));
319566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPopTab(v));
3220cf1dd8SToby Isaac   PetscFunctionReturn(0);
3320cf1dd8SToby Isaac }
3420cf1dd8SToby Isaac 
35d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscFEView_Basic(PetscFE fe, PetscViewer v)
36d71ae5a4SJacob Faibussowitsch {
3720cf1dd8SToby Isaac   PetscBool iascii;
3820cf1dd8SToby Isaac 
3920cf1dd8SToby Isaac   PetscFunctionBegin;
409566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERASCII, &iascii));
419566063dSJacob 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 */
46d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode PetscFESetUp_Basic(PetscFE fem)
47d71ae5a4SJacob Faibussowitsch {
48b9d4cb8dSJed Brown   PetscReal    *work;
4920cf1dd8SToby Isaac   PetscBLASInt *pivots;
5020cf1dd8SToby Isaac   PetscBLASInt  n, info;
5120cf1dd8SToby Isaac   PetscInt      pdim, j;
5220cf1dd8SToby Isaac 
5320cf1dd8SToby Isaac   PetscFunctionBegin;
549566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDimension(fem->dualSpace, &pdim));
559566063dSJacob 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 
629566063dSJacob Faibussowitsch     PetscCall(PetscDualSpaceGetFunctional(fem->dualSpace, j, &f));
639566063dSJacob Faibussowitsch     PetscCall(PetscQuadratureGetData(f, NULL, &Nc, &Nq, &points, &weights));
649566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(Nc * Nq * pdim, &Bf));
659566063dSJacob 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     }
749566063dSJacob Faibussowitsch     PetscCall(PetscFree(Bf));
7520cf1dd8SToby Isaac   }
76ea2bdf6dSBarry Smith 
779566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(pdim, &pivots, pdim, &work));
7820cf1dd8SToby Isaac   n = pdim;
79792fecdfSBarry Smith   PetscCallBLAS("LAPACKgetrf", LAPACKREALgetrf_(&n, &n, fem->invV, &n, pivots, &info));
8063a3b9bcSJacob Faibussowitsch   PetscCheck(!info, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error returned from LAPACKgetrf %" PetscInt_FMT, (PetscInt)info);
81792fecdfSBarry Smith   PetscCallBLAS("LAPACKgetri", LAPACKREALgetri_(&n, fem->invV, &n, pivots, work, &n, &info));
8263a3b9bcSJacob Faibussowitsch   PetscCheck(!info, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error returned from LAPACKgetri %" PetscInt_FMT, (PetscInt)info);
839566063dSJacob Faibussowitsch   PetscCall(PetscFree2(pivots, work));
8420cf1dd8SToby Isaac   PetscFunctionReturn(0);
8520cf1dd8SToby Isaac }
8620cf1dd8SToby Isaac 
87d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscFEGetDimension_Basic(PetscFE fem, PetscInt *dim)
88d71ae5a4SJacob Faibussowitsch {
8920cf1dd8SToby Isaac   PetscFunctionBegin;
909566063dSJacob 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  */
98d71ae5a4SJacob Faibussowitsch static PetscErrorCode TensorContract_Private(PetscInt m, PetscInt n, PetscInt p, PetscInt k, const PetscReal *A, const PetscReal *B, PetscReal *C)
99d71ae5a4SJacob Faibussowitsch {
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      */
1099566063dSJacob Faibussowitsch     PetscCall(PetscBLASIntCast(n, &n_));
1109566063dSJacob Faibussowitsch     PetscCall(PetscBLASIntCast(p, &p_));
1119566063dSJacob Faibussowitsch     PetscCall(PetscBLASIntCast(k, &k_));
112b9d4cb8dSJed Brown     lda = p_;
113b9d4cb8dSJed Brown     ldb = n_;
114b9d4cb8dSJed Brown     ldc = p_;
115792fecdfSBarry Smith     PetscCallBLAS("BLASgemm", BLASREALgemm_("N", "T", &p_, &n_, &k_, &one, A + i * k * p, &lda, B, &ldb, &zero, C + i * n * p, &ldc));
116b9d4cb8dSJed Brown   }
1179566063dSJacob Faibussowitsch   PetscCall(PetscLogFlops(2. * m * n * p * k));
118b9d4cb8dSJed Brown   PetscFunctionReturn(0);
119b9d4cb8dSJed Brown }
120b9d4cb8dSJed Brown 
121d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode PetscFECreateTabulation_Basic(PetscFE fem, PetscInt npoints, const PetscReal points[], PetscInt K, PetscTabulation T)
122d71ae5a4SJacob Faibussowitsch {
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;
1339566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDM(fem->dualSpace, &dm));
1349566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
1359566063dSJacob Faibussowitsch   PetscCall(PetscDualSpaceGetDimension(fem->dualSpace, &pdim));
1369566063dSJacob Faibussowitsch   PetscCall(PetscFEGetNumComponents(fem, &Nc));
13720cf1dd8SToby Isaac   /* Evaluate the prime basis functions at all points */
1389566063dSJacob Faibussowitsch   if (K >= 0) PetscCall(DMGetWorkArray(dm, npoints * pdim * Nc, MPIU_REAL, &tmpB));
1399566063dSJacob Faibussowitsch   if (K >= 1) PetscCall(DMGetWorkArray(dm, npoints * pdim * Nc * dim, MPIU_REAL, &tmpD));
1409566063dSJacob Faibussowitsch   if (K >= 2) PetscCall(DMGetWorkArray(dm, npoints * pdim * Nc * dim * dim, MPIU_REAL, &tmpH));
1419566063dSJacob 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] */
1459566063dSJacob 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] */
1499566063dSJacob 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] */
1539566063dSJacob Faibussowitsch     PetscCall(TensorContract_Private(npoints, pdim, Nc * dim * dim, pdim, tmpH, fem->invV, H));
15420cf1dd8SToby Isaac   }
1559566063dSJacob Faibussowitsch   if (K >= 0) PetscCall(DMRestoreWorkArray(dm, npoints * pdim * Nc, MPIU_REAL, &tmpB));
1569566063dSJacob Faibussowitsch   if (K >= 1) PetscCall(DMRestoreWorkArray(dm, npoints * pdim * Nc * dim, MPIU_REAL, &tmpD));
1579566063dSJacob Faibussowitsch   if (K >= 2) PetscCall(DMRestoreWorkArray(dm, npoints * pdim * Nc * dim * dim, MPIU_REAL, &tmpH));
15820cf1dd8SToby Isaac   PetscFunctionReturn(0);
15920cf1dd8SToby Isaac }
16020cf1dd8SToby Isaac 
161d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscFEIntegrate_Basic(PetscDS ds, PetscInt field, PetscInt Ne, PetscFEGeom *cgeom, const PetscScalar coefficients[], PetscDS dsAux, const PetscScalar coefficientsAux[], PetscScalar integral[])
162d71ae5a4SJacob Faibussowitsch {
16320cf1dd8SToby Isaac   const PetscInt     debug = 0;
1644bee2e38SMatthew G. Knepley   PetscFE            fe;
16520cf1dd8SToby Isaac   PetscPointFunc     obj_func;
16620cf1dd8SToby Isaac   PetscQuadrature    quad;
167ef0bb6c7SMatthew G. Knepley   PetscTabulation   *T, *TAux = NULL;
1684bee2e38SMatthew G. Knepley   PetscScalar       *u, *u_x, *a, *a_x;
16920cf1dd8SToby Isaac   const PetscScalar *constants;
17020cf1dd8SToby Isaac   PetscReal         *x;
171ef0bb6c7SMatthew G. Knepley   PetscInt          *uOff, *uOff_x, *aOff = NULL, *aOff_x = NULL;
17220cf1dd8SToby Isaac   PetscInt           dim, dE, Np, numConstants, Nf, NfAux = 0, totDim, totDimAux = 0, cOffset = 0, cOffsetAux = 0, e;
17320cf1dd8SToby Isaac   PetscBool          isAffine;
17420cf1dd8SToby Isaac   const PetscReal   *quadPoints, *quadWeights;
17520cf1dd8SToby Isaac   PetscInt           qNc, Nq, q;
17620cf1dd8SToby Isaac 
17720cf1dd8SToby Isaac   PetscFunctionBegin;
1789566063dSJacob Faibussowitsch   PetscCall(PetscDSGetObjective(ds, field, &obj_func));
17920cf1dd8SToby Isaac   if (!obj_func) PetscFunctionReturn(0);
1809566063dSJacob Faibussowitsch   PetscCall(PetscDSGetDiscretization(ds, field, (PetscObject *)&fe));
1819566063dSJacob Faibussowitsch   PetscCall(PetscFEGetSpatialDimension(fe, &dim));
1829566063dSJacob Faibussowitsch   PetscCall(PetscFEGetQuadrature(fe, &quad));
1839566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &Nf));
1849566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(ds, &totDim));
1859566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponentOffsets(ds, &uOff));
1869566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponentDerivativeOffsets(ds, &uOff_x));
1879566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTabulation(ds, &T));
1889566063dSJacob Faibussowitsch   PetscCall(PetscDSGetEvaluationArrays(ds, &u, NULL, &u_x));
1899566063dSJacob Faibussowitsch   PetscCall(PetscDSGetWorkspace(ds, &x, NULL, NULL, NULL, NULL));
1909566063dSJacob Faibussowitsch   PetscCall(PetscDSGetConstants(ds, &numConstants, &constants));
1914bee2e38SMatthew G. Knepley   if (dsAux) {
1929566063dSJacob Faibussowitsch     PetscCall(PetscDSGetNumFields(dsAux, &NfAux));
1939566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalDimension(dsAux, &totDimAux));
1949566063dSJacob Faibussowitsch     PetscCall(PetscDSGetComponentOffsets(dsAux, &aOff));
1959566063dSJacob Faibussowitsch     PetscCall(PetscDSGetComponentDerivativeOffsets(dsAux, &aOff_x));
1969566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTabulation(dsAux, &TAux));
1979566063dSJacob Faibussowitsch     PetscCall(PetscDSGetEvaluationArrays(dsAux, &a, NULL, &a_x));
19863a3b9bcSJacob Faibussowitsch     PetscCheck(T[0]->Np == TAux[0]->Np, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of tabulation points %" PetscInt_FMT " != %" PetscInt_FMT " number of auxiliary tabulation points", T[0]->Np, TAux[0]->Np);
19920cf1dd8SToby Isaac   }
2009566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights));
20163a3b9bcSJacob Faibussowitsch   PetscCheck(qNc == 1, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only supports scalar quadrature, not %" PetscInt_FMT " components", qNc);
20220cf1dd8SToby Isaac   Np       = cgeom->numPoints;
20320cf1dd8SToby Isaac   dE       = cgeom->dimEmbed;
20420cf1dd8SToby Isaac   isAffine = cgeom->isAffine;
20520cf1dd8SToby Isaac   for (e = 0; e < Ne; ++e) {
2064bee2e38SMatthew G. Knepley     PetscFEGeom fegeom;
20720cf1dd8SToby Isaac 
20827f02ce8SMatthew G. Knepley     fegeom.dim      = cgeom->dim;
20927f02ce8SMatthew G. Knepley     fegeom.dimEmbed = cgeom->dimEmbed;
21020cf1dd8SToby Isaac     if (isAffine) {
2114bee2e38SMatthew G. Knepley       fegeom.v    = x;
2124bee2e38SMatthew G. Knepley       fegeom.xi   = cgeom->xi;
2137132c3f7SMatthew G. Knepley       fegeom.J    = &cgeom->J[e * Np * dE * dE];
2147132c3f7SMatthew G. Knepley       fegeom.invJ = &cgeom->invJ[e * Np * dE * dE];
2157132c3f7SMatthew G. Knepley       fegeom.detJ = &cgeom->detJ[e * Np];
21620cf1dd8SToby Isaac     }
2174bee2e38SMatthew G. Knepley     for (q = 0; q < Nq; ++q) {
2184bee2e38SMatthew G. Knepley       PetscScalar integrand;
2194bee2e38SMatthew G. Knepley       PetscReal   w;
2204bee2e38SMatthew G. Knepley 
2214bee2e38SMatthew G. Knepley       if (isAffine) {
2227132c3f7SMatthew G. Knepley         CoordinatesRefToReal(dE, dim, fegeom.xi, &cgeom->v[e * Np * dE], fegeom.J, &quadPoints[q * dim], x);
2234bee2e38SMatthew G. Knepley       } else {
2244bee2e38SMatthew G. Knepley         fegeom.v    = &cgeom->v[(e * Np + q) * dE];
2254bee2e38SMatthew G. Knepley         fegeom.J    = &cgeom->J[(e * Np + q) * dE * dE];
2264bee2e38SMatthew G. Knepley         fegeom.invJ = &cgeom->invJ[(e * Np + q) * dE * dE];
2274bee2e38SMatthew G. Knepley         fegeom.detJ = &cgeom->detJ[e * Np + q];
2284bee2e38SMatthew G. Knepley       }
2294bee2e38SMatthew G. Knepley       w = fegeom.detJ[0] * quadWeights[q];
23020cf1dd8SToby Isaac       if (debug > 1 && q < Np) {
23163a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "  detJ: %g\n", (double)fegeom.detJ[0]));
2327be5e748SToby Isaac #if !defined(PETSC_USE_COMPLEX)
2339566063dSJacob Faibussowitsch         PetscCall(DMPrintCellMatrix(e, "invJ", dim, dim, fegeom.invJ));
23420cf1dd8SToby Isaac #endif
23520cf1dd8SToby Isaac       }
23663a3b9bcSJacob Faibussowitsch       if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  quad point %" PetscInt_FMT "\n", q));
2379566063dSJacob Faibussowitsch       PetscCall(PetscFEEvaluateFieldJets_Internal(ds, Nf, 0, q, T, &fegeom, &coefficients[cOffset], NULL, u, u_x, NULL));
2389566063dSJacob Faibussowitsch       if (dsAux) PetscCall(PetscFEEvaluateFieldJets_Internal(dsAux, NfAux, 0, q, TAux, &fegeom, &coefficientsAux[cOffsetAux], NULL, a, a_x, NULL));
2394bee2e38SMatthew 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);
2404bee2e38SMatthew G. Knepley       integrand *= w;
24120cf1dd8SToby Isaac       integral[e * Nf + field] += integrand;
2429566063dSJacob Faibussowitsch       if (debug > 1) PetscCall(PetscPrintf(PETSC_COMM_SELF, "    int: %g %g\n", (double)PetscRealPart(integrand), (double)PetscRealPart(integral[field])));
24320cf1dd8SToby Isaac     }
24420cf1dd8SToby Isaac     cOffset += totDim;
24520cf1dd8SToby Isaac     cOffsetAux += totDimAux;
24620cf1dd8SToby Isaac   }
24720cf1dd8SToby Isaac   PetscFunctionReturn(0);
24820cf1dd8SToby Isaac }
24920cf1dd8SToby Isaac 
250d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscFEIntegrateBd_Basic(PetscDS ds, PetscInt field, PetscBdPointFunc obj_func, PetscInt Ne, PetscFEGeom *fgeom, const PetscScalar coefficients[], PetscDS dsAux, const PetscScalar coefficientsAux[], PetscScalar integral[])
251d71ae5a4SJacob Faibussowitsch {
252afe6d6adSToby Isaac   const PetscInt     debug = 0;
2534bee2e38SMatthew G. Knepley   PetscFE            fe;
254afe6d6adSToby Isaac   PetscQuadrature    quad;
255ef0bb6c7SMatthew G. Knepley   PetscTabulation   *Tf, *TfAux = NULL;
2564bee2e38SMatthew G. Knepley   PetscScalar       *u, *u_x, *a, *a_x, *basisReal, *basisDerReal;
257afe6d6adSToby Isaac   const PetscScalar *constants;
258afe6d6adSToby Isaac   PetscReal         *x;
259ef0bb6c7SMatthew G. Knepley   PetscInt          *uOff, *uOff_x, *aOff = NULL, *aOff_x = NULL;
260afe6d6adSToby Isaac   PetscBool          isAffine, auxOnBd;
261afe6d6adSToby Isaac   const PetscReal   *quadPoints, *quadWeights;
262afe6d6adSToby Isaac   PetscInt           qNc, Nq, q, Np, dE;
263afe6d6adSToby Isaac   PetscInt           dim, dimAux, numConstants, Nf, NfAux = 0, totDim, totDimAux = 0, cOffset = 0, cOffsetAux = 0, e;
264afe6d6adSToby Isaac 
265afe6d6adSToby Isaac   PetscFunctionBegin;
266afe6d6adSToby Isaac   if (!obj_func) PetscFunctionReturn(0);
2679566063dSJacob Faibussowitsch   PetscCall(PetscDSGetDiscretization(ds, field, (PetscObject *)&fe));
2689566063dSJacob Faibussowitsch   PetscCall(PetscFEGetSpatialDimension(fe, &dim));
2699566063dSJacob Faibussowitsch   PetscCall(PetscFEGetFaceQuadrature(fe, &quad));
2709566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &Nf));
2719566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(ds, &totDim));
2729566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponentOffsets(ds, &uOff));
2739566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponentDerivativeOffsets(ds, &uOff_x));
2749566063dSJacob Faibussowitsch   PetscCall(PetscDSGetEvaluationArrays(ds, &u, NULL, &u_x));
2759566063dSJacob Faibussowitsch   PetscCall(PetscDSGetWorkspace(ds, &x, &basisReal, &basisDerReal, NULL, NULL));
2769566063dSJacob Faibussowitsch   PetscCall(PetscDSGetFaceTabulation(ds, &Tf));
2779566063dSJacob Faibussowitsch   PetscCall(PetscDSGetConstants(ds, &numConstants, &constants));
2784bee2e38SMatthew G. Knepley   if (dsAux) {
2799566063dSJacob Faibussowitsch     PetscCall(PetscDSGetSpatialDimension(dsAux, &dimAux));
2809566063dSJacob Faibussowitsch     PetscCall(PetscDSGetNumFields(dsAux, &NfAux));
2819566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalDimension(dsAux, &totDimAux));
2829566063dSJacob Faibussowitsch     PetscCall(PetscDSGetComponentOffsets(dsAux, &aOff));
2839566063dSJacob Faibussowitsch     PetscCall(PetscDSGetComponentDerivativeOffsets(dsAux, &aOff_x));
2849566063dSJacob Faibussowitsch     PetscCall(PetscDSGetEvaluationArrays(dsAux, &a, NULL, &a_x));
285afe6d6adSToby Isaac     auxOnBd = dimAux < dim ? PETSC_TRUE : PETSC_FALSE;
2869566063dSJacob Faibussowitsch     if (auxOnBd) PetscCall(PetscDSGetTabulation(dsAux, &TfAux));
2879566063dSJacob Faibussowitsch     else PetscCall(PetscDSGetFaceTabulation(dsAux, &TfAux));
28863a3b9bcSJacob Faibussowitsch     PetscCheck(Tf[0]->Np == TfAux[0]->Np, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of tabulation points %" PetscInt_FMT " != %" PetscInt_FMT " number of auxiliary tabulation points", Tf[0]->Np, TfAux[0]->Np);
289afe6d6adSToby Isaac   }
2909566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights));
29163a3b9bcSJacob Faibussowitsch   PetscCheck(qNc == 1, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only supports scalar quadrature, not %" PetscInt_FMT " components", qNc);
292afe6d6adSToby Isaac   Np       = fgeom->numPoints;
293afe6d6adSToby Isaac   dE       = fgeom->dimEmbed;
294afe6d6adSToby Isaac   isAffine = fgeom->isAffine;
295afe6d6adSToby Isaac   for (e = 0; e < Ne; ++e) {
2969f209ee4SMatthew G. Knepley     PetscFEGeom    fegeom, cgeom;
297afe6d6adSToby Isaac     const PetscInt face = fgeom->face[e][0]; /* Local face number in cell */
298ea78f98cSLisandro Dalcin     fegeom.n            = NULL;
299ea78f98cSLisandro Dalcin     fegeom.v            = NULL;
300ea78f98cSLisandro Dalcin     fegeom.J            = NULL;
301ea78f98cSLisandro Dalcin     fegeom.detJ         = NULL;
30227f02ce8SMatthew G. Knepley     fegeom.dim          = fgeom->dim;
30327f02ce8SMatthew G. Knepley     fegeom.dimEmbed     = fgeom->dimEmbed;
30427f02ce8SMatthew G. Knepley     cgeom.dim           = fgeom->dim;
30527f02ce8SMatthew G. Knepley     cgeom.dimEmbed      = fgeom->dimEmbed;
3064bee2e38SMatthew G. Knepley     if (isAffine) {
3074bee2e38SMatthew G. Knepley       fegeom.v    = x;
3084bee2e38SMatthew G. Knepley       fegeom.xi   = fgeom->xi;
3097132c3f7SMatthew G. Knepley       fegeom.J    = &fgeom->J[e * Np * dE * dE];
3107132c3f7SMatthew G. Knepley       fegeom.invJ = &fgeom->invJ[e * Np * dE * dE];
3117132c3f7SMatthew G. Knepley       fegeom.detJ = &fgeom->detJ[e * Np];
3127132c3f7SMatthew G. Knepley       fegeom.n    = &fgeom->n[e * Np * dE];
3139f209ee4SMatthew G. Knepley 
3147132c3f7SMatthew G. Knepley       cgeom.J    = &fgeom->suppJ[0][e * Np * dE * dE];
3157132c3f7SMatthew G. Knepley       cgeom.invJ = &fgeom->suppInvJ[0][e * Np * dE * dE];
3167132c3f7SMatthew G. Knepley       cgeom.detJ = &fgeom->suppDetJ[0][e * Np];
3174bee2e38SMatthew G. Knepley     }
318afe6d6adSToby Isaac     for (q = 0; q < Nq; ++q) {
319afe6d6adSToby Isaac       PetscScalar integrand;
3204bee2e38SMatthew G. Knepley       PetscReal   w;
321afe6d6adSToby Isaac 
322afe6d6adSToby Isaac       if (isAffine) {
3237132c3f7SMatthew G. Knepley         CoordinatesRefToReal(dE, dim - 1, fegeom.xi, &fgeom->v[e * Np * dE], fegeom.J, &quadPoints[q * (dim - 1)], x);
324afe6d6adSToby Isaac       } else {
3253fe841f2SMatthew G. Knepley         fegeom.v    = &fgeom->v[(e * Np + q) * dE];
3269f209ee4SMatthew G. Knepley         fegeom.J    = &fgeom->J[(e * Np + q) * dE * dE];
3279f209ee4SMatthew G. Knepley         fegeom.invJ = &fgeom->invJ[(e * Np + q) * dE * dE];
3284bee2e38SMatthew G. Knepley         fegeom.detJ = &fgeom->detJ[e * Np + q];
3294bee2e38SMatthew G. Knepley         fegeom.n    = &fgeom->n[(e * Np + q) * dE];
3309f209ee4SMatthew G. Knepley 
3319f209ee4SMatthew G. Knepley         cgeom.J    = &fgeom->suppJ[0][(e * Np + q) * dE * dE];
3329f209ee4SMatthew G. Knepley         cgeom.invJ = &fgeom->suppInvJ[0][(e * Np + q) * dE * dE];
3339f209ee4SMatthew G. Knepley         cgeom.detJ = &fgeom->suppDetJ[0][e * Np + q];
334afe6d6adSToby Isaac       }
3354bee2e38SMatthew G. Knepley       w = fegeom.detJ[0] * quadWeights[q];
336afe6d6adSToby Isaac       if (debug > 1 && q < Np) {
33763a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "  detJ: %g\n", (double)fegeom.detJ[0]));
338afe6d6adSToby Isaac #ifndef PETSC_USE_COMPLEX
3399566063dSJacob Faibussowitsch         PetscCall(DMPrintCellMatrix(e, "invJ", dim, dim, fegeom.invJ));
340afe6d6adSToby Isaac #endif
341afe6d6adSToby Isaac       }
34263a3b9bcSJacob Faibussowitsch       if (debug > 1) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  quad point %" PetscInt_FMT "\n", q));
3439566063dSJacob Faibussowitsch       PetscCall(PetscFEEvaluateFieldJets_Internal(ds, Nf, face, q, Tf, &cgeom, &coefficients[cOffset], NULL, u, u_x, NULL));
3449566063dSJacob Faibussowitsch       if (dsAux) PetscCall(PetscFEEvaluateFieldJets_Internal(dsAux, NfAux, face, q, TfAux, &cgeom, &coefficientsAux[cOffsetAux], NULL, a, a_x, NULL));
3454bee2e38SMatthew 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);
3464bee2e38SMatthew G. Knepley       integrand *= w;
347afe6d6adSToby Isaac       integral[e * Nf + field] += integrand;
3489566063dSJacob Faibussowitsch       if (debug > 1) PetscCall(PetscPrintf(PETSC_COMM_SELF, "    int: %g %g\n", (double)PetscRealPart(integrand), (double)PetscRealPart(integral[e * Nf + field])));
349afe6d6adSToby Isaac     }
350afe6d6adSToby Isaac     cOffset += totDim;
351afe6d6adSToby Isaac     cOffsetAux += totDimAux;
352afe6d6adSToby Isaac   }
353afe6d6adSToby Isaac   PetscFunctionReturn(0);
354afe6d6adSToby Isaac }
355afe6d6adSToby Isaac 
356d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscFEIntegrateResidual_Basic(PetscDS ds, PetscFormKey key, PetscInt Ne, PetscFEGeom *cgeom, const PetscScalar coefficients[], const PetscScalar coefficients_t[], PetscDS dsAux, const PetscScalar coefficientsAux[], PetscReal t, PetscScalar elemVec[])
357d71ae5a4SJacob Faibussowitsch {
35820cf1dd8SToby Isaac   const PetscInt     debug = 0;
3596528b96dSMatthew G. Knepley   const PetscInt     field = key.field;
3604bee2e38SMatthew G. Knepley   PetscFE            fe;
3616528b96dSMatthew G. Knepley   PetscWeakForm      wf;
3626528b96dSMatthew G. Knepley   PetscInt           n0, n1, i;
3636528b96dSMatthew G. Knepley   PetscPointFunc    *f0_func, *f1_func;
36420cf1dd8SToby Isaac   PetscQuadrature    quad;
365ef0bb6c7SMatthew G. Knepley   PetscTabulation   *T, *TAux = NULL;
3664bee2e38SMatthew G. Knepley   PetscScalar       *f0, *f1, *u, *u_t = NULL, *u_x, *a, *a_x, *basisReal, *basisDerReal;
36720cf1dd8SToby Isaac   const PetscScalar *constants;
36820cf1dd8SToby Isaac   PetscReal         *x;
369ef0bb6c7SMatthew G. Knepley   PetscInt          *uOff, *uOff_x, *aOff = NULL, *aOff_x = NULL;
370ef0bb6c7SMatthew G. Knepley   PetscInt           dim, numConstants, Nf, NfAux = 0, totDim, totDimAux = 0, cOffset = 0, cOffsetAux = 0, fOffset, e;
37120cf1dd8SToby Isaac   const PetscReal   *quadPoints, *quadWeights;
3726587ee25SMatthew G. Knepley   PetscInt           qdim, qNc, Nq, q, dE;
37320cf1dd8SToby Isaac 
37420cf1dd8SToby Isaac   PetscFunctionBegin;
3759566063dSJacob Faibussowitsch   PetscCall(PetscDSGetDiscretization(ds, field, (PetscObject *)&fe));
3769566063dSJacob Faibussowitsch   PetscCall(PetscFEGetSpatialDimension(fe, &dim));
3779566063dSJacob Faibussowitsch   PetscCall(PetscFEGetQuadrature(fe, &quad));
3789566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &Nf));
3799566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(ds, &totDim));
3809566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponentOffsets(ds, &uOff));
3819566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponentDerivativeOffsets(ds, &uOff_x));
3829566063dSJacob Faibussowitsch   PetscCall(PetscDSGetFieldOffset(ds, field, &fOffset));
3839566063dSJacob Faibussowitsch   PetscCall(PetscDSGetWeakForm(ds, &wf));
3849566063dSJacob Faibussowitsch   PetscCall(PetscWeakFormGetResidual(wf, key.label, key.value, key.field, key.part, &n0, &f0_func, &n1, &f1_func));
3856528b96dSMatthew G. Knepley   if (!n0 && !n1) PetscFunctionReturn(0);
3869566063dSJacob Faibussowitsch   PetscCall(PetscDSGetEvaluationArrays(ds, &u, coefficients_t ? &u_t : NULL, &u_x));
3879566063dSJacob Faibussowitsch   PetscCall(PetscDSGetWorkspace(ds, &x, &basisReal, &basisDerReal, NULL, NULL));
3889566063dSJacob Faibussowitsch   PetscCall(PetscDSGetWeakFormArrays(ds, &f0, &f1, NULL, NULL, NULL, NULL));
3899566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTabulation(ds, &T));
3909566063dSJacob Faibussowitsch   PetscCall(PetscDSGetConstants(ds, &numConstants, &constants));
3914bee2e38SMatthew G. Knepley   if (dsAux) {
3929566063dSJacob Faibussowitsch     PetscCall(PetscDSGetNumFields(dsAux, &NfAux));
3939566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalDimension(dsAux, &totDimAux));
3949566063dSJacob Faibussowitsch     PetscCall(PetscDSGetComponentOffsets(dsAux, &aOff));
3959566063dSJacob Faibussowitsch     PetscCall(PetscDSGetComponentDerivativeOffsets(dsAux, &aOff_x));
3969566063dSJacob Faibussowitsch     PetscCall(PetscDSGetEvaluationArrays(dsAux, &a, NULL, &a_x));
3979566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTabulation(dsAux, &TAux));
39863a3b9bcSJacob Faibussowitsch     PetscCheck(T[0]->Np == TAux[0]->Np, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of tabulation points %" PetscInt_FMT " != %" PetscInt_FMT " number of auxiliary tabulation points", T[0]->Np, TAux[0]->Np);
39920cf1dd8SToby Isaac   }
4009566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(quad, &qdim, &qNc, &Nq, &quadPoints, &quadWeights));
40163a3b9bcSJacob Faibussowitsch   PetscCheck(qNc == 1, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only supports scalar quadrature, not %" PetscInt_FMT " components", qNc);
40220cf1dd8SToby Isaac   dE = cgeom->dimEmbed;
40363a3b9bcSJacob Faibussowitsch   PetscCheck(cgeom->dim == qdim, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "FEGeom dim %" PetscInt_FMT " != %" PetscInt_FMT " quadrature dim", cgeom->dim, qdim);
40420cf1dd8SToby Isaac   for (e = 0; e < Ne; ++e) {
4054bee2e38SMatthew G. Knepley     PetscFEGeom fegeom;
40620cf1dd8SToby Isaac 
4076587ee25SMatthew G. Knepley     fegeom.v = x; /* workspace */
4089566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(f0, Nq * T[field]->Nc));
4099566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(f1, Nq * T[field]->Nc * dE));
41020cf1dd8SToby Isaac     for (q = 0; q < Nq; ++q) {
4114bee2e38SMatthew G. Knepley       PetscReal w;
4124bee2e38SMatthew G. Knepley       PetscInt  c, d;
41320cf1dd8SToby Isaac 
4149566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomGetPoint(cgeom, e, q, &quadPoints[q * cgeom->dim], &fegeom));
4154bee2e38SMatthew G. Knepley       w = fegeom.detJ[0] * quadWeights[q];
4166587ee25SMatthew G. Knepley       if (debug > 1 && q < cgeom->numPoints) {
41763a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "  detJ: %g\n", (double)fegeom.detJ[0]));
4187be5e748SToby Isaac #if !defined(PETSC_USE_COMPLEX)
4199566063dSJacob Faibussowitsch         PetscCall(DMPrintCellMatrix(e, "invJ", dim, dim, fegeom.invJ));
42020cf1dd8SToby Isaac #endif
42120cf1dd8SToby Isaac       }
4229566063dSJacob Faibussowitsch       PetscCall(PetscFEEvaluateFieldJets_Internal(ds, Nf, 0, q, T, &fegeom, &coefficients[cOffset], &coefficients_t[cOffset], u, u_x, u_t));
4239566063dSJacob Faibussowitsch       if (dsAux) PetscCall(PetscFEEvaluateFieldJets_Internal(dsAux, NfAux, 0, q, TAux, &fegeom, &coefficientsAux[cOffsetAux], NULL, a, a_x, NULL));
4246528b96dSMatthew 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]);
425ef0bb6c7SMatthew G. Knepley       for (c = 0; c < T[field]->Nc; ++c) f0[q * T[field]->Nc + c] *= w;
4266528b96dSMatthew 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]);
4279371c9d4SSatish Balay       for (c = 0; c < T[field]->Nc; ++c)
4289371c9d4SSatish Balay         for (d = 0; d < dim; ++d) f1[(q * T[field]->Nc + c) * dim + d] *= w;
429b8025e53SMatthew G. Knepley       if (debug) {
43063a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "  quad point %" PetscInt_FMT " wt %g\n", q, (double)quadWeights[q]));
431b8025e53SMatthew G. Knepley         if (debug > 2) {
43263a3b9bcSJacob Faibussowitsch           PetscCall(PetscPrintf(PETSC_COMM_SELF, "  field %" PetscInt_FMT ":", field));
43363a3b9bcSJacob Faibussowitsch           for (c = 0; c < T[field]->Nc; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %g", (double)PetscRealPart(u[uOff[field] + c])));
4349566063dSJacob Faibussowitsch           PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
43563a3b9bcSJacob Faibussowitsch           PetscCall(PetscPrintf(PETSC_COMM_SELF, "  resid %" PetscInt_FMT ":", field));
43663a3b9bcSJacob Faibussowitsch           for (c = 0; c < T[field]->Nc; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %g", (double)PetscRealPart(f0[q * T[field]->Nc + c])));
4379566063dSJacob Faibussowitsch           PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
438b8025e53SMatthew G. Knepley         }
439b8025e53SMatthew G. Knepley       }
44020cf1dd8SToby Isaac     }
4419566063dSJacob Faibussowitsch     PetscCall(PetscFEUpdateElementVec_Internal(fe, T[field], 0, basisReal, basisDerReal, e, cgeom, f0, f1, &elemVec[cOffset + fOffset]));
44220cf1dd8SToby Isaac     cOffset += totDim;
44320cf1dd8SToby Isaac     cOffsetAux += totDimAux;
44420cf1dd8SToby Isaac   }
44520cf1dd8SToby Isaac   PetscFunctionReturn(0);
44620cf1dd8SToby Isaac }
44720cf1dd8SToby Isaac 
448d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscFEIntegrateBdResidual_Basic(PetscDS ds, PetscWeakForm wf, PetscFormKey key, PetscInt Ne, PetscFEGeom *fgeom, const PetscScalar coefficients[], const PetscScalar coefficients_t[], PetscDS dsAux, const PetscScalar coefficientsAux[], PetscReal t, PetscScalar elemVec[])
449d71ae5a4SJacob Faibussowitsch {
45020cf1dd8SToby Isaac   const PetscInt     debug = 0;
45106d8a0d3SMatthew G. Knepley   const PetscInt     field = key.field;
4524bee2e38SMatthew G. Knepley   PetscFE            fe;
45306d8a0d3SMatthew G. Knepley   PetscInt           n0, n1, i;
45406d8a0d3SMatthew G. Knepley   PetscBdPointFunc  *f0_func, *f1_func;
45520cf1dd8SToby Isaac   PetscQuadrature    quad;
456ef0bb6c7SMatthew G. Knepley   PetscTabulation   *Tf, *TfAux = NULL;
4574bee2e38SMatthew G. Knepley   PetscScalar       *f0, *f1, *u, *u_t = NULL, *u_x, *a, *a_x, *basisReal, *basisDerReal;
45820cf1dd8SToby Isaac   const PetscScalar *constants;
45920cf1dd8SToby Isaac   PetscReal         *x;
460ef0bb6c7SMatthew G. Knepley   PetscInt          *uOff, *uOff_x, *aOff = NULL, *aOff_x = NULL;
461ef0bb6c7SMatthew G. Knepley   PetscInt           dim, dimAux, numConstants, Nf, NfAux = 0, totDim, totDimAux = 0, cOffset = 0, cOffsetAux = 0, fOffset, e, NcI;
4626587ee25SMatthew G. Knepley   PetscBool          auxOnBd = PETSC_FALSE;
46320cf1dd8SToby Isaac   const PetscReal   *quadPoints, *quadWeights;
4646587ee25SMatthew G. Knepley   PetscInt           qdim, qNc, Nq, q, dE;
46520cf1dd8SToby Isaac 
46620cf1dd8SToby Isaac   PetscFunctionBegin;
4679566063dSJacob Faibussowitsch   PetscCall(PetscDSGetDiscretization(ds, field, (PetscObject *)&fe));
4689566063dSJacob Faibussowitsch   PetscCall(PetscFEGetSpatialDimension(fe, &dim));
4699566063dSJacob Faibussowitsch   PetscCall(PetscFEGetFaceQuadrature(fe, &quad));
4709566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &Nf));
4719566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(ds, &totDim));
4729566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponentOffsets(ds, &uOff));
4739566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponentDerivativeOffsets(ds, &uOff_x));
4749566063dSJacob Faibussowitsch   PetscCall(PetscDSGetFieldOffset(ds, field, &fOffset));
4759566063dSJacob Faibussowitsch   PetscCall(PetscWeakFormGetBdResidual(wf, key.label, key.value, key.field, key.part, &n0, &f0_func, &n1, &f1_func));
47606d8a0d3SMatthew G. Knepley   if (!n0 && !n1) PetscFunctionReturn(0);
4779566063dSJacob Faibussowitsch   PetscCall(PetscDSGetEvaluationArrays(ds, &u, coefficients_t ? &u_t : NULL, &u_x));
4789566063dSJacob Faibussowitsch   PetscCall(PetscDSGetWorkspace(ds, &x, &basisReal, &basisDerReal, NULL, NULL));
4799566063dSJacob Faibussowitsch   PetscCall(PetscDSGetWeakFormArrays(ds, &f0, &f1, NULL, NULL, NULL, NULL));
4809566063dSJacob Faibussowitsch   PetscCall(PetscDSGetFaceTabulation(ds, &Tf));
4819566063dSJacob Faibussowitsch   PetscCall(PetscDSGetConstants(ds, &numConstants, &constants));
4824bee2e38SMatthew G. Knepley   if (dsAux) {
4839566063dSJacob Faibussowitsch     PetscCall(PetscDSGetSpatialDimension(dsAux, &dimAux));
4849566063dSJacob Faibussowitsch     PetscCall(PetscDSGetNumFields(dsAux, &NfAux));
4859566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalDimension(dsAux, &totDimAux));
4869566063dSJacob Faibussowitsch     PetscCall(PetscDSGetComponentOffsets(dsAux, &aOff));
4879566063dSJacob Faibussowitsch     PetscCall(PetscDSGetComponentDerivativeOffsets(dsAux, &aOff_x));
4889566063dSJacob Faibussowitsch     PetscCall(PetscDSGetEvaluationArrays(dsAux, &a, NULL, &a_x));
4897be5e748SToby Isaac     auxOnBd = dimAux < dim ? PETSC_TRUE : PETSC_FALSE;
4909566063dSJacob Faibussowitsch     if (auxOnBd) PetscCall(PetscDSGetTabulation(dsAux, &TfAux));
4919566063dSJacob Faibussowitsch     else PetscCall(PetscDSGetFaceTabulation(dsAux, &TfAux));
49263a3b9bcSJacob Faibussowitsch     PetscCheck(Tf[0]->Np == TfAux[0]->Np, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of tabulation points %" PetscInt_FMT " != %" PetscInt_FMT " number of auxiliary tabulation points", Tf[0]->Np, TfAux[0]->Np);
49320cf1dd8SToby Isaac   }
494ef0bb6c7SMatthew G. Knepley   NcI = Tf[field]->Nc;
4959566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(quad, &qdim, &qNc, &Nq, &quadPoints, &quadWeights));
49663a3b9bcSJacob Faibussowitsch   PetscCheck(qNc == 1, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only supports scalar quadrature, not %" PetscInt_FMT " components", qNc);
49720cf1dd8SToby Isaac   dE = fgeom->dimEmbed;
4986587ee25SMatthew G. Knepley   /* TODO FIX THIS */
4996587ee25SMatthew G. Knepley   fgeom->dim = dim - 1;
50063a3b9bcSJacob Faibussowitsch   PetscCheck(fgeom->dim == qdim, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "FEGeom dim %" PetscInt_FMT " != %" PetscInt_FMT " quadrature dim", fgeom->dim, qdim);
50120cf1dd8SToby Isaac   for (e = 0; e < Ne; ++e) {
5029f209ee4SMatthew G. Knepley     PetscFEGeom    fegeom, cgeom;
50320cf1dd8SToby Isaac     const PetscInt face = fgeom->face[e][0];
5049f209ee4SMatthew G. Knepley 
5056587ee25SMatthew G. Knepley     fegeom.v = x; /* Workspace */
5069566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(f0, Nq * NcI));
5079566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(f1, Nq * NcI * dE));
50820cf1dd8SToby Isaac     for (q = 0; q < Nq; ++q) {
5094bee2e38SMatthew G. Knepley       PetscReal w;
5104bee2e38SMatthew G. Knepley       PetscInt  c, d;
5114bee2e38SMatthew G. Knepley 
5129566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomGetPoint(fgeom, e, q, &quadPoints[q * fgeom->dim], &fegeom));
5139566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomGetCellPoint(fgeom, e, q, &cgeom));
5144bee2e38SMatthew G. Knepley       w = fegeom.detJ[0] * quadWeights[q];
51562bd480fSMatthew G. Knepley       if (debug > 1) {
5166587ee25SMatthew G. Knepley         if ((fgeom->isAffine && q == 0) || (!fgeom->isAffine)) {
51763a3b9bcSJacob Faibussowitsch           PetscCall(PetscPrintf(PETSC_COMM_SELF, "  detJ: %g\n", (double)fegeom.detJ[0]));
5187be5e748SToby Isaac #if !defined(PETSC_USE_COMPLEX)
5199566063dSJacob Faibussowitsch           PetscCall(DMPrintCellMatrix(e, "invJ", dim, dim, fegeom.invJ));
5209566063dSJacob Faibussowitsch           PetscCall(DMPrintCellVector(e, "n", dim, fegeom.n));
52120cf1dd8SToby Isaac #endif
52220cf1dd8SToby Isaac         }
52362bd480fSMatthew G. Knepley       }
5249566063dSJacob Faibussowitsch       PetscCall(PetscFEEvaluateFieldJets_Internal(ds, Nf, face, q, Tf, &cgeom, &coefficients[cOffset], &coefficients_t[cOffset], u, u_x, u_t));
5259566063dSJacob Faibussowitsch       if (dsAux) PetscCall(PetscFEEvaluateFieldJets_Internal(dsAux, NfAux, auxOnBd ? 0 : face, q, TfAux, &cgeom, &coefficientsAux[cOffsetAux], NULL, a, a_x, NULL));
52606d8a0d3SMatthew 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]);
5274bee2e38SMatthew G. Knepley       for (c = 0; c < NcI; ++c) f0[q * NcI + c] *= w;
52806d8a0d3SMatthew 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]);
5299371c9d4SSatish Balay       for (c = 0; c < NcI; ++c)
5309371c9d4SSatish Balay         for (d = 0; d < dim; ++d) f1[(q * NcI + c) * dim + d] *= w;
53162bd480fSMatthew G. Knepley       if (debug) {
53263a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "  elem %" PetscInt_FMT " quad point %" PetscInt_FMT "\n", e, q));
53362bd480fSMatthew G. Knepley         for (c = 0; c < NcI; ++c) {
53463a3b9bcSJacob Faibussowitsch           if (n0) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  f0[%" PetscInt_FMT "] %g\n", c, (double)PetscRealPart(f0[q * NcI + c])));
53562bd480fSMatthew G. Knepley           if (n1) {
53663a3b9bcSJacob Faibussowitsch             for (d = 0; d < dim; ++d) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  f1[%" PetscInt_FMT ",%" PetscInt_FMT "] %g", c, d, (double)PetscRealPart(f1[(q * NcI + c) * dim + d])));
5379566063dSJacob Faibussowitsch             PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
53862bd480fSMatthew G. Knepley           }
53962bd480fSMatthew G. Knepley         }
54062bd480fSMatthew G. Knepley       }
54120cf1dd8SToby Isaac     }
5429566063dSJacob Faibussowitsch     PetscCall(PetscFEUpdateElementVec_Internal(fe, Tf[field], face, basisReal, basisDerReal, e, fgeom, f0, f1, &elemVec[cOffset + fOffset]));
54320cf1dd8SToby Isaac     cOffset += totDim;
54420cf1dd8SToby Isaac     cOffsetAux += totDimAux;
54520cf1dd8SToby Isaac   }
54620cf1dd8SToby Isaac   PetscFunctionReturn(0);
54720cf1dd8SToby Isaac }
54820cf1dd8SToby Isaac 
54927f02ce8SMatthew G. Knepley /*
55027f02ce8SMatthew 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
55127f02ce8SMatthew G. Knepley               all transforms operate in the full space and are square.
55227f02ce8SMatthew G. Knepley 
55327f02ce8SMatthew G. Knepley   HybridIntegral: The discretization is lower dimensional. That means the transforms are non-square.
55427f02ce8SMatthew G. Knepley     1) DMPlexGetCellFields() retrieves from the hybrid cell, so it gets fields from both faces
55527f02ce8SMatthew G. Knepley     2) We need to assume that the orientation is 0 for both
55627f02ce8SMatthew 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()
55727f02ce8SMatthew G. Knepley */
558d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscFEIntegrateHybridResidual_Basic(PetscDS ds, PetscFormKey key, PetscInt s, PetscInt Ne, PetscFEGeom *fgeom, const PetscScalar coefficients[], const PetscScalar coefficients_t[], PetscDS dsAux, const PetscScalar coefficientsAux[], PetscReal t, PetscScalar elemVec[])
559d71ae5a4SJacob Faibussowitsch {
56027f02ce8SMatthew G. Knepley   const PetscInt     debug = 0;
5616528b96dSMatthew G. Knepley   const PetscInt     field = key.field;
56227f02ce8SMatthew G. Knepley   PetscFE            fe;
5636528b96dSMatthew G. Knepley   PetscWeakForm      wf;
5646528b96dSMatthew G. Knepley   PetscInt           n0, n1, i;
5656528b96dSMatthew G. Knepley   PetscBdPointFunc  *f0_func, *f1_func;
56627f02ce8SMatthew G. Knepley   PetscQuadrature    quad;
567665f567fSMatthew G. Knepley   PetscTabulation   *Tf, *TfAux = NULL;
56827f02ce8SMatthew G. Knepley   PetscScalar       *f0, *f1, *u, *u_t = NULL, *u_x, *a, *a_x, *basisReal, *basisDerReal;
56927f02ce8SMatthew G. Knepley   const PetscScalar *constants;
57027f02ce8SMatthew G. Knepley   PetscReal         *x;
571665f567fSMatthew G. Knepley   PetscInt          *uOff, *uOff_x, *aOff = NULL, *aOff_x = NULL;
572665f567fSMatthew G. Knepley   PetscInt           dim, dimAux, numConstants, Nf, NfAux = 0, totDim, totDimAux = 0, cOffset = 0, cOffsetAux = 0, fOffset, e, NcI, NcS;
5736587ee25SMatthew G. Knepley   PetscBool          isCohesiveField, auxOnBd = PETSC_FALSE;
57427f02ce8SMatthew G. Knepley   const PetscReal   *quadPoints, *quadWeights;
5756587ee25SMatthew G. Knepley   PetscInt           qdim, qNc, Nq, q, dE;
57627f02ce8SMatthew G. Knepley 
57727f02ce8SMatthew G. Knepley   PetscFunctionBegin;
57827f02ce8SMatthew G. Knepley   /* Hybrid discretization is posed directly on faces */
5799566063dSJacob Faibussowitsch   PetscCall(PetscDSGetDiscretization(ds, field, (PetscObject *)&fe));
5809566063dSJacob Faibussowitsch   PetscCall(PetscFEGetSpatialDimension(fe, &dim));
5819566063dSJacob Faibussowitsch   PetscCall(PetscFEGetQuadrature(fe, &quad));
5829566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &Nf));
5839566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(ds, &totDim));
5849566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponentOffsetsCohesive(ds, s, &uOff));
5859566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponentDerivativeOffsetsCohesive(ds, s, &uOff_x));
5869566063dSJacob Faibussowitsch   PetscCall(PetscDSGetFieldOffsetCohesive(ds, field, &fOffset));
5879566063dSJacob Faibussowitsch   PetscCall(PetscDSGetWeakForm(ds, &wf));
5889566063dSJacob Faibussowitsch   PetscCall(PetscWeakFormGetBdResidual(wf, key.label, key.value, key.field, key.part, &n0, &f0_func, &n1, &f1_func));
5896528b96dSMatthew G. Knepley   if (!n0 && !n1) PetscFunctionReturn(0);
5909566063dSJacob Faibussowitsch   PetscCall(PetscDSGetEvaluationArrays(ds, &u, coefficients_t ? &u_t : NULL, &u_x));
5919566063dSJacob Faibussowitsch   PetscCall(PetscDSGetWorkspace(ds, &x, &basisReal, &basisDerReal, NULL, NULL));
5929566063dSJacob Faibussowitsch   PetscCall(PetscDSGetWeakFormArrays(ds, &f0, &f1, NULL, NULL, NULL, NULL));
59327f02ce8SMatthew G. Knepley   /* NOTE This is a bulk tabulation because the DS is a face discretization */
5949566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTabulation(ds, &Tf));
5959566063dSJacob Faibussowitsch   PetscCall(PetscDSGetConstants(ds, &numConstants, &constants));
59627f02ce8SMatthew G. Knepley   if (dsAux) {
5979566063dSJacob Faibussowitsch     PetscCall(PetscDSGetSpatialDimension(dsAux, &dimAux));
5989566063dSJacob Faibussowitsch     PetscCall(PetscDSGetNumFields(dsAux, &NfAux));
5999566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalDimension(dsAux, &totDimAux));
6009566063dSJacob Faibussowitsch     PetscCall(PetscDSGetComponentOffsets(dsAux, &aOff));
6019566063dSJacob Faibussowitsch     PetscCall(PetscDSGetComponentDerivativeOffsets(dsAux, &aOff_x));
6029566063dSJacob Faibussowitsch     PetscCall(PetscDSGetEvaluationArrays(dsAux, &a, NULL, &a_x));
60301907d53SMatthew G. Knepley     auxOnBd = dimAux == dim ? PETSC_TRUE : PETSC_FALSE;
6049566063dSJacob Faibussowitsch     if (auxOnBd) PetscCall(PetscDSGetTabulation(dsAux, &TfAux));
6059566063dSJacob Faibussowitsch     else PetscCall(PetscDSGetFaceTabulation(dsAux, &TfAux));
60663a3b9bcSJacob Faibussowitsch     PetscCheck(Tf[0]->Np == TfAux[0]->Np, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of tabulation points %" PetscInt_FMT " != %" PetscInt_FMT " number of auxiliary tabulation points", Tf[0]->Np, TfAux[0]->Np);
60727f02ce8SMatthew G. Knepley   }
6089566063dSJacob Faibussowitsch   PetscCall(PetscDSGetCohesive(ds, field, &isCohesiveField));
609665f567fSMatthew G. Knepley   NcI = Tf[field]->Nc;
610c2b7495fSMatthew G. Knepley   NcS = NcI;
6119566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(quad, &qdim, &qNc, &Nq, &quadPoints, &quadWeights));
61263a3b9bcSJacob Faibussowitsch   PetscCheck(qNc == 1, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only supports scalar quadrature, not %" PetscInt_FMT " components", qNc);
61327f02ce8SMatthew G. Knepley   dE = fgeom->dimEmbed;
61463a3b9bcSJacob Faibussowitsch   PetscCheck(fgeom->dim == qdim, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "FEGeom dim %" PetscInt_FMT " != %" PetscInt_FMT " quadrature dim", fgeom->dim, qdim);
61527f02ce8SMatthew G. Knepley   for (e = 0; e < Ne; ++e) {
61627f02ce8SMatthew G. Knepley     PetscFEGeom    fegeom;
61727f02ce8SMatthew G. Knepley     const PetscInt face = fgeom->face[e][0];
61827f02ce8SMatthew G. Knepley 
6196587ee25SMatthew G. Knepley     fegeom.v = x; /* Workspace */
6209566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(f0, Nq * NcS));
6219566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(f1, Nq * NcS * dE));
62227f02ce8SMatthew G. Knepley     for (q = 0; q < Nq; ++q) {
62327f02ce8SMatthew G. Knepley       PetscReal w;
62427f02ce8SMatthew G. Knepley       PetscInt  c, d;
62527f02ce8SMatthew G. Knepley 
6269566063dSJacob Faibussowitsch       PetscCall(PetscFEGeomGetPoint(fgeom, e, q, &quadPoints[q * fgeom->dim], &fegeom));
62727f02ce8SMatthew G. Knepley       w = fegeom.detJ[0] * quadWeights[q];
6286587ee25SMatthew G. Knepley       if (debug > 1 && q < fgeom->numPoints) {
62963a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "  detJ: %g\n", (double)fegeom.detJ[0]));
63027f02ce8SMatthew G. Knepley #if !defined(PETSC_USE_COMPLEX)
6319566063dSJacob Faibussowitsch         PetscCall(DMPrintCellMatrix(e, "invJ", dim, dE, fegeom.invJ));
63227f02ce8SMatthew G. Knepley #endif
63327f02ce8SMatthew G. Knepley       }
634a4158a15SMatthew G. Knepley       if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  quad point %" PetscInt_FMT " weight %g detJ %g\n", q, (double)quadWeights[q], (double)fegeom.detJ[0]));
63527f02ce8SMatthew G. Knepley       /* TODO Is this cell or face quadrature, meaning should we use 'q' or 'face*Nq+q' */
6369566063dSJacob Faibussowitsch       PetscCall(PetscFEEvaluateFieldJets_Hybrid_Internal(ds, Nf, 0, q, Tf, &fegeom, &coefficients[cOffset], &coefficients_t[cOffset], u, u_x, u_t));
6379566063dSJacob Faibussowitsch       if (dsAux) PetscCall(PetscFEEvaluateFieldJets_Internal(dsAux, NfAux, 0, auxOnBd ? q : face * Nq + q, TfAux, &fegeom, &coefficientsAux[cOffsetAux], NULL, a, a_x, NULL));
6386528b96dSMatthew 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]);
63927f02ce8SMatthew G. Knepley       for (c = 0; c < NcS; ++c) f0[q * NcS + c] *= w;
6409ee2af8cSMatthew 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]);
6419371c9d4SSatish Balay       for (c = 0; c < NcS; ++c)
6429371c9d4SSatish Balay         for (d = 0; d < dE; ++d) f1[(q * NcS + c) * dE + d] *= w;
64327f02ce8SMatthew G. Knepley     }
6449371c9d4SSatish Balay     if (isCohesiveField) {
6459371c9d4SSatish Balay       PetscFEUpdateElementVec_Internal(fe, Tf[field], 0, basisReal, basisDerReal, e, fgeom, f0, f1, &elemVec[cOffset + fOffset]);
6469371c9d4SSatish Balay     } else {
6479371c9d4SSatish Balay       PetscFEUpdateElementVec_Hybrid_Internal(fe, Tf[field], 0, s, basisReal, basisDerReal, fgeom, f0, f1, &elemVec[cOffset + fOffset]);
6489371c9d4SSatish Balay     }
64927f02ce8SMatthew G. Knepley     cOffset += totDim;
65027f02ce8SMatthew G. Knepley     cOffsetAux += totDimAux;
65127f02ce8SMatthew G. Knepley   }
65227f02ce8SMatthew G. Knepley   PetscFunctionReturn(0);
65327f02ce8SMatthew G. Knepley }
65427f02ce8SMatthew G. Knepley 
655d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscFEIntegrateJacobian_Basic(PetscDS ds, PetscFEJacobianType jtype, PetscFormKey key, PetscInt Ne, PetscFEGeom *cgeom, const PetscScalar coefficients[], const PetscScalar coefficients_t[], PetscDS dsAux, const PetscScalar coefficientsAux[], PetscReal t, PetscReal u_tshift, PetscScalar elemMat[])
656d71ae5a4SJacob Faibussowitsch {
65720cf1dd8SToby Isaac   const PetscInt     debug = 0;
6584bee2e38SMatthew G. Knepley   PetscFE            feI, feJ;
6596528b96dSMatthew G. Knepley   PetscWeakForm      wf;
6606528b96dSMatthew G. Knepley   PetscPointJac     *g0_func, *g1_func, *g2_func, *g3_func;
6616528b96dSMatthew G. Knepley   PetscInt           n0, n1, n2, n3, i;
66220cf1dd8SToby Isaac   PetscInt           cOffset    = 0; /* Offset into coefficients[] for element e */
66320cf1dd8SToby Isaac   PetscInt           cOffsetAux = 0; /* Offset into coefficientsAux[] for element e */
66420cf1dd8SToby Isaac   PetscInt           eOffset    = 0; /* Offset into elemMat[] for element e */
66520cf1dd8SToby Isaac   PetscInt           offsetI    = 0; /* Offset into an element vector for fieldI */
66620cf1dd8SToby Isaac   PetscInt           offsetJ    = 0; /* Offset into an element vector for fieldJ */
66720cf1dd8SToby Isaac   PetscQuadrature    quad;
668ef0bb6c7SMatthew G. Knepley   PetscTabulation   *T, *TAux = NULL;
6694bee2e38SMatthew G. Knepley   PetscScalar       *g0, *g1, *g2, *g3, *u, *u_t = NULL, *u_x, *a, *a_x, *basisReal, *basisDerReal, *testReal, *testDerReal;
67020cf1dd8SToby Isaac   const PetscScalar *constants;
67120cf1dd8SToby Isaac   PetscReal         *x;
672ef0bb6c7SMatthew G. Knepley   PetscInt          *uOff, *uOff_x, *aOff = NULL, *aOff_x = NULL;
673ef0bb6c7SMatthew G. Knepley   PetscInt           NcI = 0, NcJ = 0;
6746528b96dSMatthew G. Knepley   PetscInt           dim, numConstants, Nf, fieldI, fieldJ, NfAux = 0, totDim, totDimAux = 0, e;
67520cf1dd8SToby Isaac   PetscInt           dE, Np;
67620cf1dd8SToby Isaac   PetscBool          isAffine;
67720cf1dd8SToby Isaac   const PetscReal   *quadPoints, *quadWeights;
67820cf1dd8SToby Isaac   PetscInt           qNc, Nq, q;
67920cf1dd8SToby Isaac 
68020cf1dd8SToby Isaac   PetscFunctionBegin;
6819566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &Nf));
6826528b96dSMatthew G. Knepley   fieldI = key.field / Nf;
6836528b96dSMatthew G. Knepley   fieldJ = key.field % Nf;
6849566063dSJacob Faibussowitsch   PetscCall(PetscDSGetDiscretization(ds, fieldI, (PetscObject *)&feI));
6859566063dSJacob Faibussowitsch   PetscCall(PetscDSGetDiscretization(ds, fieldJ, (PetscObject *)&feJ));
6869566063dSJacob Faibussowitsch   PetscCall(PetscFEGetSpatialDimension(feI, &dim));
6879566063dSJacob Faibussowitsch   PetscCall(PetscFEGetQuadrature(feI, &quad));
6889566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(ds, &totDim));
6899566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponentOffsets(ds, &uOff));
6909566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponentDerivativeOffsets(ds, &uOff_x));
6919566063dSJacob Faibussowitsch   PetscCall(PetscDSGetWeakForm(ds, &wf));
69220cf1dd8SToby Isaac   switch (jtype) {
693d71ae5a4SJacob Faibussowitsch   case PETSCFE_JACOBIAN_DYN:
694d71ae5a4SJacob Faibussowitsch     PetscCall(PetscWeakFormGetDynamicJacobian(wf, key.label, key.value, fieldI, fieldJ, key.part, &n0, &g0_func, &n1, &g1_func, &n2, &g2_func, &n3, &g3_func));
695d71ae5a4SJacob Faibussowitsch     break;
696d71ae5a4SJacob Faibussowitsch   case PETSCFE_JACOBIAN_PRE:
697d71ae5a4SJacob Faibussowitsch     PetscCall(PetscWeakFormGetJacobianPreconditioner(wf, key.label, key.value, fieldI, fieldJ, key.part, &n0, &g0_func, &n1, &g1_func, &n2, &g2_func, &n3, &g3_func));
698d71ae5a4SJacob Faibussowitsch     break;
699d71ae5a4SJacob Faibussowitsch   case PETSCFE_JACOBIAN:
700d71ae5a4SJacob Faibussowitsch     PetscCall(PetscWeakFormGetJacobian(wf, key.label, key.value, fieldI, fieldJ, key.part, &n0, &g0_func, &n1, &g1_func, &n2, &g2_func, &n3, &g3_func));
701d71ae5a4SJacob Faibussowitsch     break;
70220cf1dd8SToby Isaac   }
7036528b96dSMatthew G. Knepley   if (!n0 && !n1 && !n2 && !n3) PetscFunctionReturn(0);
7049566063dSJacob Faibussowitsch   PetscCall(PetscDSGetEvaluationArrays(ds, &u, coefficients_t ? &u_t : NULL, &u_x));
7059566063dSJacob Faibussowitsch   PetscCall(PetscDSGetWorkspace(ds, &x, &basisReal, &basisDerReal, &testReal, &testDerReal));
7069566063dSJacob Faibussowitsch   PetscCall(PetscDSGetWeakFormArrays(ds, NULL, NULL, &g0, &g1, &g2, &g3));
7079566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTabulation(ds, &T));
7089566063dSJacob Faibussowitsch   PetscCall(PetscDSGetFieldOffset(ds, fieldI, &offsetI));
7099566063dSJacob Faibussowitsch   PetscCall(PetscDSGetFieldOffset(ds, fieldJ, &offsetJ));
7109566063dSJacob Faibussowitsch   PetscCall(PetscDSGetConstants(ds, &numConstants, &constants));
7114bee2e38SMatthew G. Knepley   if (dsAux) {
7129566063dSJacob Faibussowitsch     PetscCall(PetscDSGetNumFields(dsAux, &NfAux));
7139566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalDimension(dsAux, &totDimAux));
7149566063dSJacob Faibussowitsch     PetscCall(PetscDSGetComponentOffsets(dsAux, &aOff));
7159566063dSJacob Faibussowitsch     PetscCall(PetscDSGetComponentDerivativeOffsets(dsAux, &aOff_x));
7169566063dSJacob Faibussowitsch     PetscCall(PetscDSGetEvaluationArrays(dsAux, &a, NULL, &a_x));
7179566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTabulation(dsAux, &TAux));
71863a3b9bcSJacob Faibussowitsch     PetscCheck(T[0]->Np == TAux[0]->Np, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of tabulation points %" PetscInt_FMT " != %" PetscInt_FMT " number of auxiliary tabulation points", T[0]->Np, TAux[0]->Np);
71920cf1dd8SToby Isaac   }
72027f02ce8SMatthew G. Knepley   NcI      = T[fieldI]->Nc;
72127f02ce8SMatthew G. Knepley   NcJ      = T[fieldJ]->Nc;
7224bee2e38SMatthew G. Knepley   Np       = cgeom->numPoints;
7234bee2e38SMatthew G. Knepley   dE       = cgeom->dimEmbed;
7244bee2e38SMatthew G. Knepley   isAffine = cgeom->isAffine;
72527f02ce8SMatthew G. Knepley   /* Initialize here in case the function is not defined */
7269566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(g0, NcI * NcJ));
7279566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(g1, NcI * NcJ * dE));
7289566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(g2, NcI * NcJ * dE));
7299566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(g3, NcI * NcJ * dE * dE));
7309566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights));
73163a3b9bcSJacob Faibussowitsch   PetscCheck(qNc == 1, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only supports scalar quadrature, not %" PetscInt_FMT " components", qNc);
7324bee2e38SMatthew G. Knepley   for (e = 0; e < Ne; ++e) {
7334bee2e38SMatthew G. Knepley     PetscFEGeom fegeom;
7344bee2e38SMatthew G. Knepley 
73527f02ce8SMatthew G. Knepley     fegeom.dim      = cgeom->dim;
73627f02ce8SMatthew G. Knepley     fegeom.dimEmbed = cgeom->dimEmbed;
7374bee2e38SMatthew G. Knepley     if (isAffine) {
7384bee2e38SMatthew G. Knepley       fegeom.v    = x;
7394bee2e38SMatthew G. Knepley       fegeom.xi   = cgeom->xi;
7407132c3f7SMatthew G. Knepley       fegeom.J    = &cgeom->J[e * Np * dE * dE];
7417132c3f7SMatthew G. Knepley       fegeom.invJ = &cgeom->invJ[e * Np * dE * dE];
7427132c3f7SMatthew G. Knepley       fegeom.detJ = &cgeom->detJ[e * Np];
7434bee2e38SMatthew G. Knepley     }
74420cf1dd8SToby Isaac     for (q = 0; q < Nq; ++q) {
74520cf1dd8SToby Isaac       PetscReal w;
7464bee2e38SMatthew G. Knepley       PetscInt  c;
74720cf1dd8SToby Isaac 
74820cf1dd8SToby Isaac       if (isAffine) {
7497132c3f7SMatthew G. Knepley         CoordinatesRefToReal(dE, dim, fegeom.xi, &cgeom->v[e * Np * dE], fegeom.J, &quadPoints[q * dim], x);
75020cf1dd8SToby Isaac       } else {
7514bee2e38SMatthew G. Knepley         fegeom.v    = &cgeom->v[(e * Np + q) * dE];
7524bee2e38SMatthew G. Knepley         fegeom.J    = &cgeom->J[(e * Np + q) * dE * dE];
7534bee2e38SMatthew G. Knepley         fegeom.invJ = &cgeom->invJ[(e * Np + q) * dE * dE];
7544bee2e38SMatthew G. Knepley         fegeom.detJ = &cgeom->detJ[e * Np + q];
75520cf1dd8SToby Isaac       }
7569566063dSJacob 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]));
7574bee2e38SMatthew G. Knepley       w = fegeom.detJ[0] * quadWeights[q];
7589566063dSJacob Faibussowitsch       if (coefficients) PetscCall(PetscFEEvaluateFieldJets_Internal(ds, Nf, 0, q, T, &fegeom, &coefficients[cOffset], &coefficients_t[cOffset], u, u_x, u_t));
7599566063dSJacob Faibussowitsch       if (dsAux) PetscCall(PetscFEEvaluateFieldJets_Internal(dsAux, NfAux, 0, q, TAux, &fegeom, &coefficientsAux[cOffsetAux], NULL, a, a_x, NULL));
760ea672e62SMatthew G. Knepley       if (n0) {
7619566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(g0, NcI * NcJ));
7626528b96dSMatthew 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);
76320cf1dd8SToby Isaac         for (c = 0; c < NcI * NcJ; ++c) g0[c] *= w;
76420cf1dd8SToby Isaac       }
765ea672e62SMatthew G. Knepley       if (n1) {
7669566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(g1, NcI * NcJ * dE));
7676528b96dSMatthew 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);
7684bee2e38SMatthew G. Knepley         for (c = 0; c < NcI * NcJ * dim; ++c) g1[c] *= w;
76920cf1dd8SToby Isaac       }
770ea672e62SMatthew G. Knepley       if (n2) {
7719566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(g2, NcI * NcJ * dE));
7726528b96dSMatthew 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);
7734bee2e38SMatthew G. Knepley         for (c = 0; c < NcI * NcJ * dim; ++c) g2[c] *= w;
77420cf1dd8SToby Isaac       }
775ea672e62SMatthew G. Knepley       if (n3) {
7769566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(g3, NcI * NcJ * dE * dE));
7776528b96dSMatthew 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);
7784bee2e38SMatthew G. Knepley         for (c = 0; c < NcI * NcJ * dim * dim; ++c) g3[c] *= w;
77920cf1dd8SToby Isaac       }
78020cf1dd8SToby Isaac 
7819566063dSJacob 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));
78220cf1dd8SToby Isaac     }
78320cf1dd8SToby Isaac     if (debug > 1) {
78420cf1dd8SToby Isaac       PetscInt fc, f, gc, g;
78520cf1dd8SToby Isaac 
78663a3b9bcSJacob Faibussowitsch       PetscCall(PetscPrintf(PETSC_COMM_SELF, "Element matrix for fields %" PetscInt_FMT " and %" PetscInt_FMT "\n", fieldI, fieldJ));
787ef0bb6c7SMatthew G. Knepley       for (fc = 0; fc < T[fieldI]->Nc; ++fc) {
788ef0bb6c7SMatthew G. Knepley         for (f = 0; f < T[fieldI]->Nb; ++f) {
789ef0bb6c7SMatthew G. Knepley           const PetscInt i = offsetI + f * T[fieldI]->Nc + fc;
790ef0bb6c7SMatthew G. Knepley           for (gc = 0; gc < T[fieldJ]->Nc; ++gc) {
791ef0bb6c7SMatthew G. Knepley             for (g = 0; g < T[fieldJ]->Nb; ++g) {
792ef0bb6c7SMatthew G. Knepley               const PetscInt j = offsetJ + g * T[fieldJ]->Nc + gc;
79363a3b9bcSJacob Faibussowitsch               PetscCall(PetscPrintf(PETSC_COMM_SELF, "    elemMat[%" PetscInt_FMT ",%" PetscInt_FMT ",%" PetscInt_FMT ",%" PetscInt_FMT "]: %g\n", f, fc, g, gc, (double)PetscRealPart(elemMat[eOffset + i * totDim + j])));
79420cf1dd8SToby Isaac             }
79520cf1dd8SToby Isaac           }
7969566063dSJacob Faibussowitsch           PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
79720cf1dd8SToby Isaac         }
79820cf1dd8SToby Isaac       }
79920cf1dd8SToby Isaac     }
80020cf1dd8SToby Isaac     cOffset += totDim;
80120cf1dd8SToby Isaac     cOffsetAux += totDimAux;
80220cf1dd8SToby Isaac     eOffset += PetscSqr(totDim);
80320cf1dd8SToby Isaac   }
80420cf1dd8SToby Isaac   PetscFunctionReturn(0);
80520cf1dd8SToby Isaac }
80620cf1dd8SToby Isaac 
807d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscFEIntegrateBdJacobian_Basic(PetscDS ds, PetscWeakForm wf, PetscFormKey key, PetscInt Ne, PetscFEGeom *fgeom, const PetscScalar coefficients[], const PetscScalar coefficients_t[], PetscDS dsAux, const PetscScalar coefficientsAux[], PetscReal t, PetscReal u_tshift, PetscScalar elemMat[])
808d71ae5a4SJacob Faibussowitsch {
80920cf1dd8SToby Isaac   const PetscInt     debug = 0;
8104bee2e38SMatthew G. Knepley   PetscFE            feI, feJ;
81145480ffeSMatthew G. Knepley   PetscBdPointJac   *g0_func, *g1_func, *g2_func, *g3_func;
81245480ffeSMatthew G. Knepley   PetscInt           n0, n1, n2, n3, i;
81320cf1dd8SToby Isaac   PetscInt           cOffset    = 0; /* Offset into coefficients[] for element e */
81420cf1dd8SToby Isaac   PetscInt           cOffsetAux = 0; /* Offset into coefficientsAux[] for element e */
81520cf1dd8SToby Isaac   PetscInt           eOffset    = 0; /* Offset into elemMat[] for element e */
81620cf1dd8SToby Isaac   PetscInt           offsetI    = 0; /* Offset into an element vector for fieldI */
81720cf1dd8SToby Isaac   PetscInt           offsetJ    = 0; /* Offset into an element vector for fieldJ */
81820cf1dd8SToby Isaac   PetscQuadrature    quad;
819ef0bb6c7SMatthew G. Knepley   PetscTabulation   *T, *TAux = NULL;
8204bee2e38SMatthew G. Knepley   PetscScalar       *g0, *g1, *g2, *g3, *u, *u_t = NULL, *u_x, *a, *a_x, *basisReal, *basisDerReal, *testReal, *testDerReal;
82120cf1dd8SToby Isaac   const PetscScalar *constants;
82220cf1dd8SToby Isaac   PetscReal         *x;
823ef0bb6c7SMatthew G. Knepley   PetscInt          *uOff, *uOff_x, *aOff = NULL, *aOff_x = NULL;
824ef0bb6c7SMatthew G. Knepley   PetscInt           NcI = 0, NcJ = 0;
82545480ffeSMatthew G. Knepley   PetscInt           dim, numConstants, Nf, fieldI, fieldJ, NfAux = 0, totDim, totDimAux = 0, e;
82620cf1dd8SToby Isaac   PetscBool          isAffine;
82720cf1dd8SToby Isaac   const PetscReal   *quadPoints, *quadWeights;
82820cf1dd8SToby Isaac   PetscInt           qNc, Nq, q, Np, dE;
82920cf1dd8SToby Isaac 
83020cf1dd8SToby Isaac   PetscFunctionBegin;
8319566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &Nf));
83245480ffeSMatthew G. Knepley   fieldI = key.field / Nf;
83345480ffeSMatthew G. Knepley   fieldJ = key.field % Nf;
8349566063dSJacob Faibussowitsch   PetscCall(PetscDSGetDiscretization(ds, fieldI, (PetscObject *)&feI));
8359566063dSJacob Faibussowitsch   PetscCall(PetscDSGetDiscretization(ds, fieldJ, (PetscObject *)&feJ));
8369566063dSJacob Faibussowitsch   PetscCall(PetscFEGetSpatialDimension(feI, &dim));
8379566063dSJacob Faibussowitsch   PetscCall(PetscFEGetFaceQuadrature(feI, &quad));
8389566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(ds, &totDim));
8399566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponentOffsets(ds, &uOff));
8409566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponentDerivativeOffsets(ds, &uOff_x));
8419566063dSJacob Faibussowitsch   PetscCall(PetscDSGetFieldOffset(ds, fieldI, &offsetI));
8429566063dSJacob Faibussowitsch   PetscCall(PetscDSGetFieldOffset(ds, fieldJ, &offsetJ));
8439566063dSJacob Faibussowitsch   PetscCall(PetscWeakFormGetBdJacobian(wf, key.label, key.value, fieldI, fieldJ, key.part, &n0, &g0_func, &n1, &g1_func, &n2, &g2_func, &n3, &g3_func));
84445480ffeSMatthew G. Knepley   if (!n0 && !n1 && !n2 && !n3) PetscFunctionReturn(0);
8459566063dSJacob Faibussowitsch   PetscCall(PetscDSGetEvaluationArrays(ds, &u, coefficients_t ? &u_t : NULL, &u_x));
8469566063dSJacob Faibussowitsch   PetscCall(PetscDSGetWorkspace(ds, &x, &basisReal, &basisDerReal, &testReal, &testDerReal));
8479566063dSJacob Faibussowitsch   PetscCall(PetscDSGetWeakFormArrays(ds, NULL, NULL, &g0, &g1, &g2, &g3));
8489566063dSJacob Faibussowitsch   PetscCall(PetscDSGetFaceTabulation(ds, &T));
8499566063dSJacob Faibussowitsch   PetscCall(PetscDSGetConstants(ds, &numConstants, &constants));
8504bee2e38SMatthew G. Knepley   if (dsAux) {
8519566063dSJacob Faibussowitsch     PetscCall(PetscDSGetNumFields(dsAux, &NfAux));
8529566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalDimension(dsAux, &totDimAux));
8539566063dSJacob Faibussowitsch     PetscCall(PetscDSGetComponentOffsets(dsAux, &aOff));
8549566063dSJacob Faibussowitsch     PetscCall(PetscDSGetComponentDerivativeOffsets(dsAux, &aOff_x));
8559566063dSJacob Faibussowitsch     PetscCall(PetscDSGetEvaluationArrays(dsAux, &a, NULL, &a_x));
8569566063dSJacob Faibussowitsch     PetscCall(PetscDSGetFaceTabulation(dsAux, &TAux));
85720cf1dd8SToby Isaac   }
858ef0bb6c7SMatthew G. Knepley   NcI = T[fieldI]->Nc, NcJ = T[fieldJ]->Nc;
85920cf1dd8SToby Isaac   Np       = fgeom->numPoints;
86020cf1dd8SToby Isaac   dE       = fgeom->dimEmbed;
86120cf1dd8SToby Isaac   isAffine = fgeom->isAffine;
86227f02ce8SMatthew G. Knepley   /* Initialize here in case the function is not defined */
8639566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(g0, NcI * NcJ));
8649566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(g1, NcI * NcJ * dE));
8659566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(g2, NcI * NcJ * dE));
8669566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(g3, NcI * NcJ * dE * dE));
8679566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights));
86863a3b9bcSJacob Faibussowitsch   PetscCheck(qNc == 1, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only supports scalar quadrature, not %" PetscInt_FMT " components", qNc);
86920cf1dd8SToby Isaac   for (e = 0; e < Ne; ++e) {
8709f209ee4SMatthew G. Knepley     PetscFEGeom    fegeom, cgeom;
87120cf1dd8SToby Isaac     const PetscInt face = fgeom->face[e][0];
872ea78f98cSLisandro Dalcin     fegeom.n            = NULL;
873ea78f98cSLisandro Dalcin     fegeom.v            = NULL;
874ea78f98cSLisandro Dalcin     fegeom.J            = NULL;
875ea78f98cSLisandro Dalcin     fegeom.detJ         = NULL;
87627f02ce8SMatthew G. Knepley     fegeom.dim          = fgeom->dim;
87727f02ce8SMatthew G. Knepley     fegeom.dimEmbed     = fgeom->dimEmbed;
87827f02ce8SMatthew G. Knepley     cgeom.dim           = fgeom->dim;
87927f02ce8SMatthew G. Knepley     cgeom.dimEmbed      = fgeom->dimEmbed;
8804bee2e38SMatthew G. Knepley     if (isAffine) {
8814bee2e38SMatthew G. Knepley       fegeom.v    = x;
8824bee2e38SMatthew G. Knepley       fegeom.xi   = fgeom->xi;
8837132c3f7SMatthew G. Knepley       fegeom.J    = &fgeom->J[e * Np * dE * dE];
8847132c3f7SMatthew G. Knepley       fegeom.invJ = &fgeom->invJ[e * Np * dE * dE];
8857132c3f7SMatthew G. Knepley       fegeom.detJ = &fgeom->detJ[e * Np];
8867132c3f7SMatthew G. Knepley       fegeom.n    = &fgeom->n[e * Np * dE];
8879f209ee4SMatthew G. Knepley 
8887132c3f7SMatthew G. Knepley       cgeom.J    = &fgeom->suppJ[0][e * Np * dE * dE];
8897132c3f7SMatthew G. Knepley       cgeom.invJ = &fgeom->suppInvJ[0][e * Np * dE * dE];
8907132c3f7SMatthew G. Knepley       cgeom.detJ = &fgeom->suppDetJ[0][e * Np];
8914bee2e38SMatthew G. Knepley     }
89220cf1dd8SToby Isaac     for (q = 0; q < Nq; ++q) {
89320cf1dd8SToby Isaac       PetscReal w;
8944bee2e38SMatthew G. Knepley       PetscInt  c;
89520cf1dd8SToby Isaac 
89663a3b9bcSJacob Faibussowitsch       if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  quad point %" PetscInt_FMT "\n", q));
89720cf1dd8SToby Isaac       if (isAffine) {
8987132c3f7SMatthew G. Knepley         CoordinatesRefToReal(dE, dim - 1, fegeom.xi, &fgeom->v[e * Np * dE], fegeom.J, &quadPoints[q * (dim - 1)], x);
89920cf1dd8SToby Isaac       } else {
9003fe841f2SMatthew G. Knepley         fegeom.v    = &fgeom->v[(e * Np + q) * dE];
9019f209ee4SMatthew G. Knepley         fegeom.J    = &fgeom->J[(e * Np + q) * dE * dE];
9029f209ee4SMatthew G. Knepley         fegeom.invJ = &fgeom->invJ[(e * Np + q) * dE * dE];
9034bee2e38SMatthew G. Knepley         fegeom.detJ = &fgeom->detJ[e * Np + q];
9044bee2e38SMatthew G. Knepley         fegeom.n    = &fgeom->n[(e * Np + q) * dE];
9059f209ee4SMatthew G. Knepley 
9069f209ee4SMatthew G. Knepley         cgeom.J    = &fgeom->suppJ[0][(e * Np + q) * dE * dE];
9079f209ee4SMatthew G. Knepley         cgeom.invJ = &fgeom->suppInvJ[0][(e * Np + q) * dE * dE];
9089f209ee4SMatthew G. Knepley         cgeom.detJ = &fgeom->suppDetJ[0][e * Np + q];
90920cf1dd8SToby Isaac       }
9104bee2e38SMatthew G. Knepley       w = fegeom.detJ[0] * quadWeights[q];
9119566063dSJacob Faibussowitsch       if (coefficients) PetscCall(PetscFEEvaluateFieldJets_Internal(ds, Nf, face, q, T, &cgeom, &coefficients[cOffset], &coefficients_t[cOffset], u, u_x, u_t));
9129566063dSJacob Faibussowitsch       if (dsAux) PetscCall(PetscFEEvaluateFieldJets_Internal(dsAux, NfAux, face, q, TAux, &cgeom, &coefficientsAux[cOffsetAux], NULL, a, a_x, NULL));
913ea672e62SMatthew G. Knepley       if (n0) {
9149566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(g0, NcI * NcJ));
91545480ffeSMatthew 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);
91620cf1dd8SToby Isaac         for (c = 0; c < NcI * NcJ; ++c) g0[c] *= w;
91720cf1dd8SToby Isaac       }
918ea672e62SMatthew G. Knepley       if (n1) {
9199566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(g1, NcI * NcJ * dE));
92045480ffeSMatthew 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);
9214bee2e38SMatthew G. Knepley         for (c = 0; c < NcI * NcJ * dim; ++c) g1[c] *= w;
92220cf1dd8SToby Isaac       }
923ea672e62SMatthew G. Knepley       if (n2) {
9249566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(g2, NcI * NcJ * dE));
92545480ffeSMatthew 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);
9264bee2e38SMatthew G. Knepley         for (c = 0; c < NcI * NcJ * dim; ++c) g2[c] *= w;
92720cf1dd8SToby Isaac       }
928ea672e62SMatthew G. Knepley       if (n3) {
9299566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(g3, NcI * NcJ * dE * dE));
93045480ffeSMatthew 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);
9314bee2e38SMatthew G. Knepley         for (c = 0; c < NcI * NcJ * dim * dim; ++c) g3[c] *= w;
93220cf1dd8SToby Isaac       }
93320cf1dd8SToby Isaac 
9349566063dSJacob 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));
93520cf1dd8SToby Isaac     }
93620cf1dd8SToby Isaac     if (debug > 1) {
93720cf1dd8SToby Isaac       PetscInt fc, f, gc, g;
93820cf1dd8SToby Isaac 
93963a3b9bcSJacob Faibussowitsch       PetscCall(PetscPrintf(PETSC_COMM_SELF, "Element matrix for fields %" PetscInt_FMT " and %" PetscInt_FMT "\n", fieldI, fieldJ));
940ef0bb6c7SMatthew G. Knepley       for (fc = 0; fc < T[fieldI]->Nc; ++fc) {
941ef0bb6c7SMatthew G. Knepley         for (f = 0; f < T[fieldI]->Nb; ++f) {
942ef0bb6c7SMatthew G. Knepley           const PetscInt i = offsetI + f * T[fieldI]->Nc + fc;
943ef0bb6c7SMatthew G. Knepley           for (gc = 0; gc < T[fieldJ]->Nc; ++gc) {
944ef0bb6c7SMatthew G. Knepley             for (g = 0; g < T[fieldJ]->Nb; ++g) {
945ef0bb6c7SMatthew G. Knepley               const PetscInt j = offsetJ + g * T[fieldJ]->Nc + gc;
94663a3b9bcSJacob Faibussowitsch               PetscCall(PetscPrintf(PETSC_COMM_SELF, "    elemMat[%" PetscInt_FMT ",%" PetscInt_FMT ",%" PetscInt_FMT ",%" PetscInt_FMT "]: %g\n", f, fc, g, gc, (double)PetscRealPart(elemMat[eOffset + i * totDim + j])));
94720cf1dd8SToby Isaac             }
94820cf1dd8SToby Isaac           }
9499566063dSJacob Faibussowitsch           PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
95020cf1dd8SToby Isaac         }
95120cf1dd8SToby Isaac       }
95220cf1dd8SToby Isaac     }
95320cf1dd8SToby Isaac     cOffset += totDim;
95420cf1dd8SToby Isaac     cOffsetAux += totDimAux;
95520cf1dd8SToby Isaac     eOffset += PetscSqr(totDim);
95620cf1dd8SToby Isaac   }
95720cf1dd8SToby Isaac   PetscFunctionReturn(0);
95820cf1dd8SToby Isaac }
95920cf1dd8SToby Isaac 
960d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscFEIntegrateHybridJacobian_Basic(PetscDS ds, PetscFEJacobianType jtype, PetscFormKey key, PetscInt s, PetscInt Ne, PetscFEGeom *fgeom, const PetscScalar coefficients[], const PetscScalar coefficients_t[], PetscDS dsAux, const PetscScalar coefficientsAux[], PetscReal t, PetscReal u_tshift, PetscScalar elemMat[])
961d71ae5a4SJacob Faibussowitsch {
96227f02ce8SMatthew G. Knepley   const PetscInt     debug = 0;
96327f02ce8SMatthew G. Knepley   PetscFE            feI, feJ;
964148442b3SMatthew G. Knepley   PetscWeakForm      wf;
965148442b3SMatthew G. Knepley   PetscBdPointJac   *g0_func, *g1_func, *g2_func, *g3_func;
966148442b3SMatthew G. Knepley   PetscInt           n0, n1, n2, n3, i;
96727f02ce8SMatthew G. Knepley   PetscInt           cOffset    = 0; /* Offset into coefficients[] for element e */
96827f02ce8SMatthew G. Knepley   PetscInt           cOffsetAux = 0; /* Offset into coefficientsAux[] for element e */
96927f02ce8SMatthew G. Knepley   PetscInt           eOffset    = 0; /* Offset into elemMat[] for element e */
97027f02ce8SMatthew G. Knepley   PetscInt           offsetI    = 0; /* Offset into an element vector for fieldI */
97127f02ce8SMatthew G. Knepley   PetscInt           offsetJ    = 0; /* Offset into an element vector for fieldJ */
972665f567fSMatthew G. Knepley   PetscQuadrature    quad;
973665f567fSMatthew G. Knepley   PetscTabulation   *T, *TAux = NULL;
97427f02ce8SMatthew G. Knepley   PetscScalar       *g0, *g1, *g2, *g3, *u, *u_t = NULL, *u_x, *a, *a_x, *basisReal, *basisDerReal, *testReal, *testDerReal;
97527f02ce8SMatthew G. Knepley   const PetscScalar *constants;
97627f02ce8SMatthew G. Knepley   PetscReal         *x;
977665f567fSMatthew G. Knepley   PetscInt          *uOff, *uOff_x, *aOff = NULL, *aOff_x = NULL;
978665f567fSMatthew G. Knepley   PetscInt           NcI = 0, NcJ = 0, NcS, NcT;
97945480ffeSMatthew G. Knepley   PetscInt           dim, dimAux, numConstants, Nf, fieldI, fieldJ, NfAux = 0, totDim, totDimAux = 0, e;
980665f567fSMatthew G. Knepley   PetscBool          isCohesiveFieldI, isCohesiveFieldJ, isAffine, auxOnBd = PETSC_FALSE;
98127f02ce8SMatthew G. Knepley   const PetscReal   *quadPoints, *quadWeights;
98227f02ce8SMatthew G. Knepley   PetscInt           qNc, Nq, q, Np, dE;
98327f02ce8SMatthew G. Knepley 
98427f02ce8SMatthew G. Knepley   PetscFunctionBegin;
9859566063dSJacob Faibussowitsch   PetscCall(PetscDSGetNumFields(ds, &Nf));
98645480ffeSMatthew G. Knepley   fieldI = key.field / Nf;
98745480ffeSMatthew G. Knepley   fieldJ = key.field % Nf;
98827f02ce8SMatthew G. Knepley   /* Hybrid discretization is posed directly on faces */
9899566063dSJacob Faibussowitsch   PetscCall(PetscDSGetDiscretization(ds, fieldI, (PetscObject *)&feI));
9909566063dSJacob Faibussowitsch   PetscCall(PetscDSGetDiscretization(ds, fieldJ, (PetscObject *)&feJ));
9919566063dSJacob Faibussowitsch   PetscCall(PetscFEGetSpatialDimension(feI, &dim));
9929566063dSJacob Faibussowitsch   PetscCall(PetscFEGetQuadrature(feI, &quad));
9939566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTotalDimension(ds, &totDim));
9949566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponentOffsetsCohesive(ds, s, &uOff));
9959566063dSJacob Faibussowitsch   PetscCall(PetscDSGetComponentDerivativeOffsetsCohesive(ds, s, &uOff_x));
9969566063dSJacob Faibussowitsch   PetscCall(PetscDSGetWeakForm(ds, &wf));
99727f02ce8SMatthew G. Knepley   switch (jtype) {
998d71ae5a4SJacob Faibussowitsch   case PETSCFE_JACOBIAN_PRE:
999d71ae5a4SJacob Faibussowitsch     PetscCall(PetscWeakFormGetBdJacobianPreconditioner(wf, key.label, key.value, fieldI, fieldJ, key.part, &n0, &g0_func, &n1, &g1_func, &n2, &g2_func, &n3, &g3_func));
1000d71ae5a4SJacob Faibussowitsch     break;
1001d71ae5a4SJacob Faibussowitsch   case PETSCFE_JACOBIAN:
1002d71ae5a4SJacob Faibussowitsch     PetscCall(PetscWeakFormGetBdJacobian(wf, key.label, key.value, fieldI, fieldJ, key.part, &n0, &g0_func, &n1, &g1_func, &n2, &g2_func, &n3, &g3_func));
1003d71ae5a4SJacob Faibussowitsch     break;
1004d71ae5a4SJacob Faibussowitsch   case PETSCFE_JACOBIAN_DYN:
1005d71ae5a4SJacob Faibussowitsch     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No boundary hybrid Jacobians :)");
100627f02ce8SMatthew G. Knepley   }
1007148442b3SMatthew G. Knepley   if (!n0 && !n1 && !n2 && !n3) PetscFunctionReturn(0);
10089566063dSJacob Faibussowitsch   PetscCall(PetscDSGetEvaluationArrays(ds, &u, coefficients_t ? &u_t : NULL, &u_x));
10099566063dSJacob Faibussowitsch   PetscCall(PetscDSGetWorkspace(ds, &x, &basisReal, &basisDerReal, &testReal, &testDerReal));
10109566063dSJacob Faibussowitsch   PetscCall(PetscDSGetWeakFormArrays(ds, NULL, NULL, &g0, &g1, &g2, &g3));
10119566063dSJacob Faibussowitsch   PetscCall(PetscDSGetTabulation(ds, &T));
10129566063dSJacob Faibussowitsch   PetscCall(PetscDSGetFieldOffsetCohesive(ds, fieldI, &offsetI));
10139566063dSJacob Faibussowitsch   PetscCall(PetscDSGetFieldOffsetCohesive(ds, fieldJ, &offsetJ));
10149566063dSJacob Faibussowitsch   PetscCall(PetscDSGetConstants(ds, &numConstants, &constants));
101527f02ce8SMatthew G. Knepley   if (dsAux) {
10169566063dSJacob Faibussowitsch     PetscCall(PetscDSGetSpatialDimension(dsAux, &dimAux));
10179566063dSJacob Faibussowitsch     PetscCall(PetscDSGetNumFields(dsAux, &NfAux));
10189566063dSJacob Faibussowitsch     PetscCall(PetscDSGetTotalDimension(dsAux, &totDimAux));
10199566063dSJacob Faibussowitsch     PetscCall(PetscDSGetComponentOffsets(dsAux, &aOff));
10209566063dSJacob Faibussowitsch     PetscCall(PetscDSGetComponentDerivativeOffsets(dsAux, &aOff_x));
10219566063dSJacob Faibussowitsch     PetscCall(PetscDSGetEvaluationArrays(dsAux, &a, NULL, &a_x));
102201907d53SMatthew G. Knepley     auxOnBd = dimAux == dim ? PETSC_TRUE : PETSC_FALSE;
10239566063dSJacob Faibussowitsch     if (auxOnBd) PetscCall(PetscDSGetTabulation(dsAux, &TAux));
10249566063dSJacob Faibussowitsch     else PetscCall(PetscDSGetFaceTabulation(dsAux, &TAux));
102563a3b9bcSJacob Faibussowitsch     PetscCheck(T[0]->Np == TAux[0]->Np, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of tabulation points %" PetscInt_FMT " != %" PetscInt_FMT " number of auxiliary tabulation points", T[0]->Np, TAux[0]->Np);
102627f02ce8SMatthew G. Knepley   }
10279566063dSJacob Faibussowitsch   PetscCall(PetscDSGetCohesive(ds, fieldI, &isCohesiveFieldI));
10289566063dSJacob Faibussowitsch   PetscCall(PetscDSGetCohesive(ds, fieldJ, &isCohesiveFieldJ));
1029665f567fSMatthew G. Knepley   NcI      = T[fieldI]->Nc;
1030665f567fSMatthew G. Knepley   NcJ      = T[fieldJ]->Nc;
103127f02ce8SMatthew G. Knepley   NcS      = isCohesiveFieldI ? NcI : 2 * NcI;
103227f02ce8SMatthew G. Knepley   NcT      = isCohesiveFieldJ ? NcJ : 2 * NcJ;
103327f02ce8SMatthew G. Knepley   Np       = fgeom->numPoints;
103427f02ce8SMatthew G. Knepley   dE       = fgeom->dimEmbed;
103527f02ce8SMatthew G. Knepley   isAffine = fgeom->isAffine;
10369566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(g0, NcS * NcT));
10379566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(g1, NcS * NcT * dE));
10389566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(g2, NcS * NcT * dE));
10399566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(g3, NcS * NcT * dE * dE));
10409566063dSJacob Faibussowitsch   PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights));
104163a3b9bcSJacob Faibussowitsch   PetscCheck(qNc == 1, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only supports scalar quadrature, not %" PetscInt_FMT " components", qNc);
104227f02ce8SMatthew G. Knepley   for (e = 0; e < Ne; ++e) {
104327f02ce8SMatthew G. Knepley     PetscFEGeom    fegeom;
104427f02ce8SMatthew G. Knepley     const PetscInt face = fgeom->face[e][0];
104527f02ce8SMatthew G. Knepley 
104627f02ce8SMatthew G. Knepley     fegeom.dim      = fgeom->dim;
104727f02ce8SMatthew G. Knepley     fegeom.dimEmbed = fgeom->dimEmbed;
104827f02ce8SMatthew G. Knepley     if (isAffine) {
104927f02ce8SMatthew G. Knepley       fegeom.v    = x;
105027f02ce8SMatthew G. Knepley       fegeom.xi   = fgeom->xi;
1051a4158a15SMatthew G. Knepley       fegeom.J    = &fgeom->J[e * Np * dE * dE];
1052a4158a15SMatthew G. Knepley       fegeom.invJ = &fgeom->invJ[e * Np * dE * dE];
1053a4158a15SMatthew G. Knepley       fegeom.detJ = &fgeom->detJ[e * Np];
1054a4158a15SMatthew G. Knepley       fegeom.n    = &fgeom->n[e * dE * Np];
105527f02ce8SMatthew G. Knepley     }
105627f02ce8SMatthew G. Knepley     for (q = 0; q < Nq; ++q) {
105727f02ce8SMatthew G. Knepley       PetscReal w;
105827f02ce8SMatthew G. Knepley       PetscInt  c;
105927f02ce8SMatthew G. Knepley 
106027f02ce8SMatthew G. Knepley       if (isAffine) {
106127f02ce8SMatthew G. Knepley         /* TODO Is it correct to have 'dim' here, or should it be 'dim-1'? */
1062a4158a15SMatthew G. Knepley         CoordinatesRefToReal(dE, dim, fegeom.xi, &fgeom->v[e * Np * dE], fegeom.J, &quadPoints[q * dim], x);
106327f02ce8SMatthew G. Knepley       } else {
106427f02ce8SMatthew G. Knepley         fegeom.v    = &fegeom.v[(e * Np + q) * dE];
106527f02ce8SMatthew G. Knepley         fegeom.J    = &fgeom->J[(e * Np + q) * dE * dE];
106627f02ce8SMatthew G. Knepley         fegeom.invJ = &fgeom->invJ[(e * Np + q) * dE * dE];
106727f02ce8SMatthew G. Knepley         fegeom.detJ = &fgeom->detJ[e * Np + q];
106827f02ce8SMatthew G. Knepley         fegeom.n    = &fgeom->n[(e * Np + q) * dE];
106927f02ce8SMatthew G. Knepley       }
107027f02ce8SMatthew G. Knepley       w = fegeom.detJ[0] * quadWeights[q];
107127f02ce8SMatthew G. Knepley       if (debug > 1 && q < Np) {
107263a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "  detJ: %g\n", (double)fegeom.detJ[0]));
107327f02ce8SMatthew G. Knepley #if !defined(PETSC_USE_COMPLEX)
10749566063dSJacob Faibussowitsch         PetscCall(DMPrintCellMatrix(e, "invJ", dim, dim, fegeom.invJ));
107527f02ce8SMatthew G. Knepley #endif
107627f02ce8SMatthew G. Knepley       }
107763a3b9bcSJacob Faibussowitsch       if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  quad point %" PetscInt_FMT "\n", q));
10789566063dSJacob Faibussowitsch       if (coefficients) PetscCall(PetscFEEvaluateFieldJets_Hybrid_Internal(ds, Nf, 0, q, T, &fegeom, &coefficients[cOffset], &coefficients_t[cOffset], u, u_x, u_t));
10799566063dSJacob Faibussowitsch       if (dsAux) PetscCall(PetscFEEvaluateFieldJets_Internal(dsAux, NfAux, 0, auxOnBd ? q : face * Nq + q, TAux, &fegeom, &coefficientsAux[cOffsetAux], NULL, a, a_x, NULL));
1080ea672e62SMatthew G. Knepley       if (n0) {
10819566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(g0, NcS * NcT));
1082148442b3SMatthew 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);
108327f02ce8SMatthew G. Knepley         for (c = 0; c < NcS * NcT; ++c) g0[c] *= w;
108427f02ce8SMatthew G. Knepley       }
1085ea672e62SMatthew G. Knepley       if (n1) {
10869566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(g1, NcS * NcT * dE));
1087148442b3SMatthew 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);
108827f02ce8SMatthew G. Knepley         for (c = 0; c < NcS * NcT * dE; ++c) g1[c] *= w;
108927f02ce8SMatthew G. Knepley       }
1090ea672e62SMatthew G. Knepley       if (n2) {
10919566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(g2, NcS * NcT * dE));
1092148442b3SMatthew 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);
109327f02ce8SMatthew G. Knepley         for (c = 0; c < NcS * NcT * dE; ++c) g2[c] *= w;
109427f02ce8SMatthew G. Knepley       }
1095ea672e62SMatthew G. Knepley       if (n3) {
10969566063dSJacob Faibussowitsch         PetscCall(PetscArrayzero(g3, NcS * NcT * dE * dE));
1097148442b3SMatthew 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);
109827f02ce8SMatthew G. Knepley         for (c = 0; c < NcS * NcT * dE * dE; ++c) g3[c] *= w;
109927f02ce8SMatthew G. Knepley       }
110027f02ce8SMatthew G. Knepley 
11015fedec97SMatthew G. Knepley       if (isCohesiveFieldI) {
11025fedec97SMatthew G. Knepley         if (isCohesiveFieldJ) {
11039566063dSJacob 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));
110427f02ce8SMatthew G. Knepley         } else {
11059566063dSJacob 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));
11069566063dSJacob 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));
11075fedec97SMatthew G. Knepley         }
11089371c9d4SSatish Balay       } else
11099371c9d4SSatish Balay         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));
111027f02ce8SMatthew G. Knepley     }
111127f02ce8SMatthew G. Knepley     if (debug > 1) {
111227f02ce8SMatthew G. Knepley       PetscInt fc, f, gc, g;
111327f02ce8SMatthew G. Knepley 
111463a3b9bcSJacob Faibussowitsch       PetscCall(PetscPrintf(PETSC_COMM_SELF, "Element matrix for fields %" PetscInt_FMT " and %" PetscInt_FMT "\n", fieldI, fieldJ));
111527f02ce8SMatthew G. Knepley       for (fc = 0; fc < NcI; ++fc) {
1116665f567fSMatthew G. Knepley         for (f = 0; f < T[fieldI]->Nb; ++f) {
111727f02ce8SMatthew G. Knepley           const PetscInt i = offsetI + f * NcI + fc;
111827f02ce8SMatthew G. Knepley           for (gc = 0; gc < NcJ; ++gc) {
1119665f567fSMatthew G. Knepley             for (g = 0; g < T[fieldJ]->Nb; ++g) {
112027f02ce8SMatthew G. Knepley               const PetscInt j = offsetJ + g * NcJ + gc;
112163a3b9bcSJacob Faibussowitsch               PetscCall(PetscPrintf(PETSC_COMM_SELF, "    elemMat[%" PetscInt_FMT ",%" PetscInt_FMT ",%" PetscInt_FMT ",%" PetscInt_FMT "]: %g\n", f, fc, g, gc, (double)PetscRealPart(elemMat[eOffset + i * totDim + j])));
112227f02ce8SMatthew G. Knepley             }
112327f02ce8SMatthew G. Knepley           }
11249566063dSJacob Faibussowitsch           PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
112527f02ce8SMatthew G. Knepley         }
112627f02ce8SMatthew G. Knepley       }
112727f02ce8SMatthew G. Knepley     }
112827f02ce8SMatthew G. Knepley     cOffset += totDim;
112927f02ce8SMatthew G. Knepley     cOffsetAux += totDimAux;
113027f02ce8SMatthew G. Knepley     eOffset += PetscSqr(totDim);
113127f02ce8SMatthew G. Knepley   }
113227f02ce8SMatthew G. Knepley   PetscFunctionReturn(0);
113327f02ce8SMatthew G. Knepley }
113427f02ce8SMatthew G. Knepley 
1135d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscFEInitialize_Basic(PetscFE fem)
1136d71ae5a4SJacob Faibussowitsch {
113720cf1dd8SToby Isaac   PetscFunctionBegin;
113820cf1dd8SToby Isaac   fem->ops->setfromoptions          = NULL;
113920cf1dd8SToby Isaac   fem->ops->setup                   = PetscFESetUp_Basic;
114020cf1dd8SToby Isaac   fem->ops->view                    = PetscFEView_Basic;
114120cf1dd8SToby Isaac   fem->ops->destroy                 = PetscFEDestroy_Basic;
114220cf1dd8SToby Isaac   fem->ops->getdimension            = PetscFEGetDimension_Basic;
1143ef0bb6c7SMatthew G. Knepley   fem->ops->createtabulation        = PetscFECreateTabulation_Basic;
114420cf1dd8SToby Isaac   fem->ops->integrate               = PetscFEIntegrate_Basic;
1145afe6d6adSToby Isaac   fem->ops->integratebd             = PetscFEIntegrateBd_Basic;
114620cf1dd8SToby Isaac   fem->ops->integrateresidual       = PetscFEIntegrateResidual_Basic;
114720cf1dd8SToby Isaac   fem->ops->integratebdresidual     = PetscFEIntegrateBdResidual_Basic;
114827f02ce8SMatthew G. Knepley   fem->ops->integratehybridresidual = PetscFEIntegrateHybridResidual_Basic;
114920cf1dd8SToby Isaac   fem->ops->integratejacobianaction = NULL /* PetscFEIntegrateJacobianAction_Basic */;
115020cf1dd8SToby Isaac   fem->ops->integratejacobian       = PetscFEIntegrateJacobian_Basic;
115120cf1dd8SToby Isaac   fem->ops->integratebdjacobian     = PetscFEIntegrateBdJacobian_Basic;
115227f02ce8SMatthew G. Knepley   fem->ops->integratehybridjacobian = PetscFEIntegrateHybridJacobian_Basic;
115320cf1dd8SToby Isaac   PetscFunctionReturn(0);
115420cf1dd8SToby Isaac }
115520cf1dd8SToby Isaac 
115620cf1dd8SToby Isaac /*MC
1157*dce8aebaSBarry Smith   PETSCFEBASIC = "basic" - A `PetscFE` object that integrates with basic tiling and no vectorization
115820cf1dd8SToby Isaac 
115920cf1dd8SToby Isaac   Level: intermediate
116020cf1dd8SToby Isaac 
1161*dce8aebaSBarry Smith .seealso: `PetscFE`, `PetscFEType`, `PetscFECreate()`, `PetscFESetType()`
116220cf1dd8SToby Isaac M*/
116320cf1dd8SToby Isaac 
1164d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode PetscFECreate_Basic(PetscFE fem)
1165d71ae5a4SJacob Faibussowitsch {
116620cf1dd8SToby Isaac   PetscFE_Basic *b;
116720cf1dd8SToby Isaac 
116820cf1dd8SToby Isaac   PetscFunctionBegin;
116920cf1dd8SToby Isaac   PetscValidHeaderSpecific(fem, PETSCFE_CLASSID, 1);
11704dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&b));
117120cf1dd8SToby Isaac   fem->data = b;
117220cf1dd8SToby Isaac 
11739566063dSJacob Faibussowitsch   PetscCall(PetscFEInitialize_Basic(fem));
117420cf1dd8SToby Isaac   PetscFunctionReturn(0);
117520cf1dd8SToby Isaac }
1176