Actual source code: febasic.c
1: #include <petsc/private/petscfeimpl.h>
2: #include <petscblaslapack.h>
4: static PetscErrorCode PetscFEDestroy_Basic(PetscFE fem)
5: {
6: PetscFE_Basic *b = (PetscFE_Basic *)fem->data;
8: PetscFunctionBegin;
9: PetscCall(PetscFree(b));
10: PetscFunctionReturn(PETSC_SUCCESS);
11: }
13: static PetscErrorCode PetscFEView_Basic_Ascii(PetscFE fe, PetscViewer v)
14: {
15: PetscInt dim, Nc;
16: PetscSpace basis = NULL;
17: PetscDualSpace dual = NULL;
18: PetscQuadrature quad = NULL;
20: PetscFunctionBegin;
21: PetscCall(PetscFEGetSpatialDimension(fe, &dim));
22: PetscCall(PetscFEGetNumComponents(fe, &Nc));
23: PetscCall(PetscFEGetBasisSpace(fe, &basis));
24: PetscCall(PetscFEGetDualSpace(fe, &dual));
25: PetscCall(PetscFEGetQuadrature(fe, &quad));
26: PetscCall(PetscViewerASCIIPushTab(v));
27: PetscCall(PetscViewerASCIIPrintf(v, "Basic Finite Element in %" PetscInt_FMT " dimensions with %" PetscInt_FMT " components\n", dim, Nc));
28: if (basis) PetscCall(PetscSpaceView(basis, v));
29: if (dual) PetscCall(PetscDualSpaceView(dual, v));
30: if (quad) PetscCall(PetscQuadratureView(quad, v));
31: PetscCall(PetscViewerASCIIPopTab(v));
32: PetscFunctionReturn(PETSC_SUCCESS);
33: }
35: static PetscErrorCode PetscFEView_Basic(PetscFE fe, PetscViewer v)
36: {
37: PetscBool iascii;
39: PetscFunctionBegin;
40: PetscCall(PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERASCII, &iascii));
41: if (iascii) PetscCall(PetscFEView_Basic_Ascii(fe, v));
42: PetscFunctionReturn(PETSC_SUCCESS);
43: }
45: /* Construct the change of basis from prime basis to nodal basis */
46: PETSC_INTERN PetscErrorCode PetscFESetUp_Basic(PetscFE fem)
47: {
48: PetscReal *work;
49: PetscBLASInt *pivots;
50: PetscBLASInt n, info;
51: PetscInt pdim, j;
53: PetscFunctionBegin;
54: PetscCall(PetscDualSpaceGetDimension(fem->dualSpace, &pdim));
55: PetscCall(PetscMalloc1(pdim * pdim, &fem->invV));
56: for (j = 0; j < pdim; ++j) {
57: PetscReal *Bf;
58: PetscQuadrature f;
59: const PetscReal *points, *weights;
60: PetscInt Nc, Nq, q, k, c;
62: PetscCall(PetscDualSpaceGetFunctional(fem->dualSpace, j, &f));
63: PetscCall(PetscQuadratureGetData(f, NULL, &Nc, &Nq, &points, &weights));
64: PetscCall(PetscMalloc1(Nc * Nq * pdim, &Bf));
65: PetscCall(PetscSpaceEvaluate(fem->basisSpace, Nq, points, Bf, NULL, NULL));
66: for (k = 0; k < pdim; ++k) {
67: /* V_{jk} = n_j(\phi_k) = \int \phi_k(x) n_j(x) dx */
68: fem->invV[j * pdim + k] = 0.0;
70: for (q = 0; q < Nq; ++q) {
71: for (c = 0; c < Nc; ++c) fem->invV[j * pdim + k] += Bf[(q * pdim + k) * Nc + c] * weights[q * Nc + c];
72: }
73: }
74: PetscCall(PetscFree(Bf));
75: }
77: PetscCall(PetscMalloc2(pdim, &pivots, pdim, &work));
78: PetscCall(PetscBLASIntCast(pdim, &n));
79: PetscCallBLAS("LAPACKgetrf", LAPACKREALgetrf_(&n, &n, fem->invV, &n, pivots, &info));
80: PetscCheck(!info, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error returned from LAPACKgetrf %" PetscBLASInt_FMT, info);
81: PetscCallBLAS("LAPACKgetri", LAPACKREALgetri_(&n, fem->invV, &n, pivots, work, &n, &info));
82: PetscCheck(!info, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error returned from LAPACKgetri %" PetscBLASInt_FMT, info);
83: PetscCall(PetscFree2(pivots, work));
84: PetscFunctionReturn(PETSC_SUCCESS);
85: }
87: PetscErrorCode PetscFEGetDimension_Basic(PetscFE fem, PetscInt *dim)
88: {
89: PetscFunctionBegin;
90: PetscCall(PetscDualSpaceGetDimension(fem->dualSpace, dim));
91: PetscFunctionReturn(PETSC_SUCCESS);
92: }
94: /* Tensor contraction on the middle index,
95: * C[m,n,p] = A[m,k,p] * B[k,n]
96: * where all matrices use C-style ordering.
97: */
98: static PetscErrorCode TensorContract_Private(PetscInt m, PetscInt n, PetscInt p, PetscInt k, const PetscReal *A, const PetscReal *B, PetscReal *C)
99: {
100: PetscInt i;
102: PetscFunctionBegin;
103: PetscCheck(n && p, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Empty tensor is not allowed %" PetscInt_FMT " %" PetscInt_FMT, n, p);
104: for (i = 0; i < m; i++) {
105: PetscBLASInt n_, p_, k_, lda, ldb, ldc;
106: PetscReal one = 1, zero = 0;
107: /* Taking contiguous submatrices, we wish to comput c[n,p] = a[k,p] * B[k,n]
108: * or, in Fortran ordering, c(p,n) = a(p,k) * B(n,k)
109: */
110: PetscCall(PetscBLASIntCast(n, &n_));
111: PetscCall(PetscBLASIntCast(p, &p_));
112: PetscCall(PetscBLASIntCast(k, &k_));
113: lda = p_;
114: ldb = n_;
115: ldc = p_;
116: PetscCallBLAS("BLASgemm", BLASREALgemm_("N", "T", &p_, &n_, &k_, &one, A + i * k * p, &lda, B, &ldb, &zero, C + i * n * p, &ldc));
117: }
118: PetscCall(PetscLogFlops(2. * m * n * p * k));
119: PetscFunctionReturn(PETSC_SUCCESS);
120: }
122: PETSC_INTERN PetscErrorCode PetscFEComputeTabulation_Basic(PetscFE fem, PetscInt npoints, const PetscReal points[], PetscInt K, PetscTabulation T)
123: {
124: DM dm;
125: PetscInt pdim; /* Dimension of FE space P */
126: PetscInt dim; /* Spatial dimension */
127: PetscInt Nc; /* Field components */
128: PetscReal *B = K >= 0 ? T->T[0] : NULL;
129: PetscReal *D = K >= 1 ? T->T[1] : NULL;
130: PetscReal *H = K >= 2 ? T->T[2] : NULL;
131: PetscReal *tmpB = NULL, *tmpD = NULL, *tmpH = NULL;
133: PetscFunctionBegin;
134: PetscCall(PetscDualSpaceGetDM(fem->dualSpace, &dm));
135: PetscCall(DMGetDimension(dm, &dim));
136: PetscCall(PetscDualSpaceGetDimension(fem->dualSpace, &pdim));
137: PetscCall(PetscFEGetNumComponents(fem, &Nc));
138: /* Evaluate the prime basis functions at all points */
139: if (K >= 0) PetscCall(DMGetWorkArray(dm, npoints * pdim * Nc, MPIU_REAL, &tmpB));
140: if (K >= 1) PetscCall(DMGetWorkArray(dm, npoints * pdim * Nc * dim, MPIU_REAL, &tmpD));
141: if (K >= 2) PetscCall(DMGetWorkArray(dm, npoints * pdim * Nc * dim * dim, MPIU_REAL, &tmpH));
142: PetscCall(PetscSpaceEvaluate(fem->basisSpace, npoints, points, tmpB, tmpD, tmpH));
143: /* Translate from prime to nodal basis */
144: if (B) {
145: /* B[npoints, nodes, Nc] = tmpB[npoints, prime, Nc] * invV[prime, nodes] */
146: PetscCall(TensorContract_Private(npoints, pdim, Nc, pdim, tmpB, fem->invV, B));
147: }
148: if (D && dim) {
149: /* D[npoints, nodes, Nc, dim] = tmpD[npoints, prime, Nc, dim] * invV[prime, nodes] */
150: PetscCall(TensorContract_Private(npoints, pdim, Nc * dim, pdim, tmpD, fem->invV, D));
151: }
152: if (H && dim) {
153: /* H[npoints, nodes, Nc, dim, dim] = tmpH[npoints, prime, Nc, dim, dim] * invV[prime, nodes] */
154: PetscCall(TensorContract_Private(npoints, pdim, Nc * dim * dim, pdim, tmpH, fem->invV, H));
155: }
156: if (K >= 0) PetscCall(DMRestoreWorkArray(dm, npoints * pdim * Nc, MPIU_REAL, &tmpB));
157: if (K >= 1) PetscCall(DMRestoreWorkArray(dm, npoints * pdim * Nc * dim, MPIU_REAL, &tmpD));
158: if (K >= 2) PetscCall(DMRestoreWorkArray(dm, npoints * pdim * Nc * dim * dim, MPIU_REAL, &tmpH));
159: PetscFunctionReturn(PETSC_SUCCESS);
160: }
162: PETSC_INTERN PetscErrorCode PetscFEIntegrate_Basic(PetscDS ds, PetscInt field, PetscInt Ne, PetscFEGeom *cgeom, const PetscScalar coefficients[], PetscDS dsAux, const PetscScalar coefficientsAux[], PetscScalar integral[])
163: {
164: const PetscInt debug = ds->printIntegrate;
165: PetscFE fe;
166: PetscPointFunc obj_func;
167: PetscQuadrature quad;
168: PetscTabulation *T, *TAux = NULL;
169: PetscScalar *u, *u_x, *a, *a_x;
170: const PetscScalar *constants;
171: PetscReal *x, cellScale;
172: PetscInt *uOff, *uOff_x, *aOff = NULL, *aOff_x = NULL;
173: PetscInt dim, dE, Np, numConstants, Nf, NfAux = 0, totDim, totDimAux = 0, cOffset = 0, cOffsetAux = 0, e;
174: PetscBool isAffine;
175: const PetscReal *quadPoints, *quadWeights;
176: PetscInt qNc, Nq, q;
178: PetscFunctionBegin;
179: PetscCall(PetscDSGetObjective(ds, field, &obj_func));
180: if (!obj_func) PetscFunctionReturn(PETSC_SUCCESS);
181: PetscCall(PetscDSGetDiscretization(ds, field, (PetscObject *)&fe));
182: PetscCall(PetscFEGetSpatialDimension(fe, &dim));
183: cellScale = (PetscReal)PetscPowInt(2, dim);
184: PetscCall(PetscFEGetQuadrature(fe, &quad));
185: PetscCall(PetscDSGetNumFields(ds, &Nf));
186: PetscCall(PetscDSGetTotalDimension(ds, &totDim));
187: PetscCall(PetscDSGetComponentOffsets(ds, &uOff));
188: PetscCall(PetscDSGetComponentDerivativeOffsets(ds, &uOff_x));
189: PetscCall(PetscDSGetTabulation(ds, &T));
190: PetscCall(PetscDSGetEvaluationArrays(ds, &u, NULL, &u_x));
191: PetscCall(PetscDSGetWorkspace(ds, &x, NULL, NULL, NULL, NULL));
192: PetscCall(PetscDSSetIntegrationParameters(ds, field, PETSC_DETERMINE));
193: PetscCall(PetscDSGetConstants(ds, &numConstants, &constants));
194: if (dsAux) {
195: PetscCall(PetscDSGetNumFields(dsAux, &NfAux));
196: PetscCall(PetscDSGetTotalDimension(dsAux, &totDimAux));
197: PetscCall(PetscDSGetComponentOffsets(dsAux, &aOff));
198: PetscCall(PetscDSGetComponentDerivativeOffsets(dsAux, &aOff_x));
199: PetscCall(PetscDSGetTabulation(dsAux, &TAux));
200: PetscCall(PetscDSGetEvaluationArrays(dsAux, &a, NULL, &a_x));
201: 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);
202: }
203: PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights));
204: PetscCheck(qNc == 1, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only supports scalar quadrature, not %" PetscInt_FMT " components", qNc);
205: Np = cgeom->numPoints;
206: dE = cgeom->dimEmbed;
207: isAffine = cgeom->isAffine;
208: for (e = 0; e < Ne; ++e) {
209: PetscFEGeom fegeom;
211: fegeom.dim = cgeom->dim;
212: fegeom.dimEmbed = cgeom->dimEmbed;
213: fegeom.xi = NULL;
214: if (isAffine) {
215: fegeom.v = x;
216: fegeom.xi = cgeom->xi;
217: fegeom.J = &cgeom->J[e * Np * dE * dE];
218: fegeom.invJ = &cgeom->invJ[e * Np * dE * dE];
219: fegeom.detJ = &cgeom->detJ[e * Np];
220: }
221: for (q = 0; q < Nq; ++q) {
222: PetscScalar integrand = 0.;
223: PetscReal w;
225: if (isAffine) {
226: CoordinatesRefToReal(dE, dim, fegeom.xi, &cgeom->v[e * Np * dE], fegeom.J, &quadPoints[q * dim], x);
227: } else {
228: fegeom.v = &cgeom->v[(e * Np + q) * dE];
229: fegeom.J = &cgeom->J[(e * Np + q) * dE * dE];
230: fegeom.invJ = &cgeom->invJ[(e * Np + q) * dE * dE];
231: fegeom.detJ = &cgeom->detJ[e * Np + q];
232: }
233: PetscCall(PetscDSSetCellParameters(ds, fegeom.detJ[0] * cellScale));
234: w = fegeom.detJ[0] * quadWeights[q];
235: if (debug > 1 && q < Np) {
236: PetscCall(PetscPrintf(PETSC_COMM_SELF, " detJ: %g\n", (double)fegeom.detJ[0]));
237: #if !defined(PETSC_USE_COMPLEX)
238: PetscCall(DMPrintCellMatrix(e, "invJ", dim, dim, fegeom.invJ));
239: #endif
240: }
241: if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, " quad point %" PetscInt_FMT "\n", q));
242: PetscCall(PetscFEEvaluateFieldJets_Internal(ds, Nf, 0, q, T, &fegeom, &coefficients[cOffset], NULL, u, u_x, NULL));
243: if (dsAux) PetscCall(PetscFEEvaluateFieldJets_Internal(dsAux, NfAux, 0, q, TAux, &fegeom, &coefficientsAux[cOffsetAux], NULL, a, a_x, NULL));
244: 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);
245: integrand *= w;
246: integral[e * Nf + field] += integrand;
247: }
248: if (debug > 1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " Element Field %" PetscInt_FMT " integral: %g\n", Nf, (double)PetscRealPart(integral[e * Nf + field])));
249: cOffset += totDim;
250: cOffsetAux += totDimAux;
251: }
252: PetscFunctionReturn(PETSC_SUCCESS);
253: }
255: PETSC_INTERN PetscErrorCode PetscFEIntegrateBd_Basic(PetscDS ds, PetscInt field, PetscBdPointFunc obj_func, PetscInt Ne, PetscFEGeom *fgeom, const PetscScalar coefficients[], PetscDS dsAux, const PetscScalar coefficientsAux[], PetscScalar integral[])
256: {
257: const PetscInt debug = ds->printIntegrate;
258: PetscFE fe;
259: PetscQuadrature quad;
260: PetscTabulation *Tf, *TfAux = NULL;
261: PetscScalar *u, *u_x, *a, *a_x, *basisReal, *basisDerReal;
262: const PetscScalar *constants;
263: PetscReal *x, cellScale;
264: PetscInt *uOff, *uOff_x, *aOff = NULL, *aOff_x = NULL;
265: PetscBool isAffine, auxOnBd;
266: const PetscReal *quadPoints, *quadWeights;
267: PetscInt qNc, Nq, q, Np, dE;
268: PetscInt dim, dimAux, numConstants, Nf, NfAux = 0, totDim, totDimAux = 0, cOffset = 0, cOffsetAux = 0, e;
270: PetscFunctionBegin;
271: if (!obj_func) PetscFunctionReturn(PETSC_SUCCESS);
272: PetscCall(PetscDSGetDiscretization(ds, field, (PetscObject *)&fe));
273: PetscCall(PetscFEGetSpatialDimension(fe, &dim));
274: cellScale = (PetscReal)PetscPowInt(2, dim);
275: PetscCall(PetscFEGetFaceQuadrature(fe, &quad));
276: PetscCall(PetscDSGetNumFields(ds, &Nf));
277: PetscCall(PetscDSGetTotalDimension(ds, &totDim));
278: PetscCall(PetscDSGetComponentOffsets(ds, &uOff));
279: PetscCall(PetscDSGetComponentDerivativeOffsets(ds, &uOff_x));
280: PetscCall(PetscDSGetEvaluationArrays(ds, &u, NULL, &u_x));
281: PetscCall(PetscDSGetWorkspace(ds, &x, &basisReal, &basisDerReal, NULL, NULL));
282: PetscCall(PetscDSGetFaceTabulation(ds, &Tf));
283: PetscCall(PetscDSSetIntegrationParameters(ds, field, PETSC_DETERMINE));
284: PetscCall(PetscDSGetConstants(ds, &numConstants, &constants));
285: if (dsAux) {
286: PetscCall(PetscDSGetSpatialDimension(dsAux, &dimAux));
287: PetscCall(PetscDSGetNumFields(dsAux, &NfAux));
288: PetscCall(PetscDSGetTotalDimension(dsAux, &totDimAux));
289: PetscCall(PetscDSGetComponentOffsets(dsAux, &aOff));
290: PetscCall(PetscDSGetComponentDerivativeOffsets(dsAux, &aOff_x));
291: PetscCall(PetscDSGetEvaluationArrays(dsAux, &a, NULL, &a_x));
292: auxOnBd = dimAux < dim ? PETSC_TRUE : PETSC_FALSE;
293: if (auxOnBd) PetscCall(PetscDSGetTabulation(dsAux, &TfAux));
294: else PetscCall(PetscDSGetFaceTabulation(dsAux, &TfAux));
295: 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);
296: }
297: PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights));
298: PetscCheck(qNc == 1, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only supports scalar quadrature, not %" PetscInt_FMT " components", qNc);
299: if (debug > 1) PetscCall(PetscPrintf(PETSC_COMM_SELF, "Field: %" PetscInt_FMT " Nface: %" PetscInt_FMT " Nq: %" PetscInt_FMT "\n", field, Ne, Nq));
300: Np = fgeom->numPoints;
301: dE = fgeom->dimEmbed;
302: isAffine = fgeom->isAffine;
303: for (e = 0; e < Ne; ++e) {
304: PetscFEGeom fegeom, cgeom;
305: const PetscInt face = fgeom->face[e][0]; /* Local face number in cell */
306: fegeom.n = NULL;
307: fegeom.v = NULL;
308: fegeom.xi = NULL;
309: fegeom.J = NULL;
310: fegeom.invJ = NULL;
311: fegeom.detJ = NULL;
312: fegeom.dim = fgeom->dim;
313: fegeom.dimEmbed = fgeom->dimEmbed;
314: cgeom.dim = fgeom->dim;
315: cgeom.dimEmbed = fgeom->dimEmbed;
316: if (isAffine) {
317: fegeom.v = x;
318: fegeom.xi = fgeom->xi;
319: fegeom.J = &fgeom->J[e * Np * dE * dE];
320: fegeom.invJ = &fgeom->invJ[e * Np * dE * dE];
321: fegeom.detJ = &fgeom->detJ[e * Np];
322: fegeom.n = &fgeom->n[e * Np * dE];
324: cgeom.J = &fgeom->suppJ[0][e * Np * dE * dE];
325: cgeom.invJ = &fgeom->suppInvJ[0][e * Np * dE * dE];
326: cgeom.detJ = &fgeom->suppDetJ[0][e * Np];
327: }
328: for (q = 0; q < Nq; ++q) {
329: PetscScalar integrand = 0.;
330: PetscReal w;
332: if (isAffine) {
333: CoordinatesRefToReal(dE, dim - 1, fegeom.xi, &fgeom->v[e * Np * dE], fegeom.J, &quadPoints[q * (dim - 1)], x);
334: } else {
335: fegeom.v = &fgeom->v[(e * Np + q) * dE];
336: fegeom.J = &fgeom->J[(e * Np + q) * dE * dE];
337: fegeom.invJ = &fgeom->invJ[(e * Np + q) * dE * dE];
338: fegeom.detJ = &fgeom->detJ[e * Np + q];
339: fegeom.n = &fgeom->n[(e * Np + q) * dE];
341: cgeom.J = &fgeom->suppJ[0][(e * Np + q) * dE * dE];
342: cgeom.invJ = &fgeom->suppInvJ[0][(e * Np + q) * dE * dE];
343: cgeom.detJ = &fgeom->suppDetJ[0][e * Np + q];
344: }
345: PetscCall(PetscDSSetCellParameters(ds, fegeom.detJ[0] * cellScale));
346: w = fegeom.detJ[0] * quadWeights[q];
347: if (debug > 1 && q < Np) {
348: PetscCall(PetscPrintf(PETSC_COMM_SELF, " detJ: %g\n", (double)fegeom.detJ[0]));
349: #ifndef PETSC_USE_COMPLEX
350: PetscCall(DMPrintCellMatrix(e, "invJ", dim, dim, fegeom.invJ));
351: #endif
352: }
353: if (debug > 1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " quad point %" PetscInt_FMT "\n", q));
354: if (debug > 3) {
355: PetscCall(PetscPrintf(PETSC_COMM_SELF, " x_q ("));
356: for (PetscInt d = 0; d < dE; ++d) {
357: if (d) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", "));
358: PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g", (double)fegeom.v[d]));
359: }
360: PetscCall(PetscPrintf(PETSC_COMM_SELF, ")\n"));
361: PetscCall(PetscPrintf(PETSC_COMM_SELF, " n_q ("));
362: for (PetscInt d = 0; d < dE; ++d) {
363: if (d) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", "));
364: PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g", (double)fegeom.n[d]));
365: }
366: PetscCall(PetscPrintf(PETSC_COMM_SELF, ")\n"));
367: for (PetscInt f = 0; f < Nf; ++f) {
368: PetscCall(PetscPrintf(PETSC_COMM_SELF, " u_%" PetscInt_FMT " (", f));
369: for (PetscInt c = 0; c < uOff[f + 1] - uOff[f]; ++c) {
370: if (c) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", "));
371: PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g", (double)PetscRealPart(u[uOff[f] + c])));
372: }
373: PetscCall(PetscPrintf(PETSC_COMM_SELF, ")\n"));
374: }
375: }
376: PetscCall(PetscFEEvaluateFieldJets_Internal(ds, Nf, face, q, Tf, &cgeom, &coefficients[cOffset], NULL, u, u_x, NULL));
377: if (dsAux) PetscCall(PetscFEEvaluateFieldJets_Internal(dsAux, NfAux, face, q, TfAux, &cgeom, &coefficientsAux[cOffsetAux], NULL, a, a_x, NULL));
378: 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);
379: integrand *= w;
380: integral[e * Nf + field] += integrand;
381: if (debug > 1) PetscCall(PetscPrintf(PETSC_COMM_SELF, " int: %g tot: %g\n", (double)PetscRealPart(integrand), (double)PetscRealPart(integral[e * Nf + field])));
382: }
383: cOffset += totDim;
384: cOffsetAux += totDimAux;
385: }
386: PetscFunctionReturn(PETSC_SUCCESS);
387: }
389: 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[])
390: {
391: const PetscInt debug = ds->printIntegrate;
392: const PetscInt field = key.field;
393: PetscFE fe;
394: PetscWeakForm wf;
395: PetscInt n0, n1, i;
396: PetscPointFunc *f0_func, *f1_func;
397: PetscQuadrature quad;
398: PetscTabulation *T, *TAux = NULL;
399: PetscScalar *f0, *f1, *u, *u_t = NULL, *u_x, *a, *a_x, *basisReal, *basisDerReal;
400: const PetscScalar *constants;
401: PetscReal *x, cellScale;
402: PetscInt *uOff, *uOff_x, *aOff = NULL, *aOff_x = NULL;
403: PetscInt dim, numConstants, Nf, NfAux = 0, totDim, totDimAux = 0, cOffset = 0, cOffsetAux = 0, fOffset, e;
404: const PetscReal *quadPoints, *quadWeights;
405: PetscInt qdim, qNc, Nq, q, dE;
407: PetscFunctionBegin;
408: PetscCall(PetscDSGetDiscretization(ds, field, (PetscObject *)&fe));
409: PetscCall(PetscFEGetSpatialDimension(fe, &dim));
410: cellScale = (PetscReal)PetscPowInt(2, dim);
411: PetscCall(PetscFEGetQuadrature(fe, &quad));
412: PetscCall(PetscDSGetNumFields(ds, &Nf));
413: PetscCall(PetscDSGetTotalDimension(ds, &totDim));
414: PetscCall(PetscDSGetComponentOffsets(ds, &uOff));
415: PetscCall(PetscDSGetComponentDerivativeOffsets(ds, &uOff_x));
416: PetscCall(PetscDSGetFieldOffset(ds, field, &fOffset));
417: PetscCall(PetscDSGetWeakForm(ds, &wf));
418: PetscCall(PetscWeakFormGetResidual(wf, key.label, key.value, key.field, key.part, &n0, &f0_func, &n1, &f1_func));
419: if (!n0 && !n1) PetscFunctionReturn(PETSC_SUCCESS);
420: PetscCall(PetscDSGetEvaluationArrays(ds, &u, coefficients_t ? &u_t : NULL, &u_x));
421: PetscCall(PetscDSGetWorkspace(ds, &x, &basisReal, &basisDerReal, NULL, NULL));
422: PetscCall(PetscDSGetWeakFormArrays(ds, &f0, &f1, NULL, NULL, NULL, NULL));
423: PetscCall(PetscDSGetTabulation(ds, &T));
424: PetscCall(PetscDSSetIntegrationParameters(ds, field, PETSC_DETERMINE));
425: PetscCall(PetscDSGetConstants(ds, &numConstants, &constants));
426: if (dsAux) {
427: PetscCall(PetscDSGetNumFields(dsAux, &NfAux));
428: PetscCall(PetscDSGetTotalDimension(dsAux, &totDimAux));
429: PetscCall(PetscDSGetComponentOffsets(dsAux, &aOff));
430: PetscCall(PetscDSGetComponentDerivativeOffsets(dsAux, &aOff_x));
431: PetscCall(PetscDSGetEvaluationArrays(dsAux, &a, NULL, &a_x));
432: PetscCall(PetscDSGetTabulation(dsAux, &TAux));
433: 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);
434: }
435: PetscCall(PetscQuadratureGetData(quad, &qdim, &qNc, &Nq, &quadPoints, &quadWeights));
436: PetscCheck(qNc == 1, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only supports scalar quadrature, not %" PetscInt_FMT " components", qNc);
437: dE = cgeom->dimEmbed;
438: PetscCheck(cgeom->dim == qdim, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "FEGeom dim %" PetscInt_FMT " != %" PetscInt_FMT " quadrature dim", cgeom->dim, qdim);
439: for (e = 0; e < Ne; ++e) {
440: PetscFEGeom fegeom;
442: fegeom.v = x; /* workspace */
443: PetscCall(PetscArrayzero(f0, Nq * T[field]->Nc));
444: PetscCall(PetscArrayzero(f1, Nq * T[field]->Nc * dE));
445: for (q = 0; q < Nq; ++q) {
446: PetscReal w;
447: PetscInt c, d;
449: PetscCall(PetscFEGeomGetPoint(cgeom, e, q, &quadPoints[q * cgeom->dim], &fegeom));
450: PetscCall(PetscDSSetCellParameters(ds, fegeom.detJ[0] * cellScale));
451: w = fegeom.detJ[0] * quadWeights[q];
452: if (debug > 1 && q < cgeom->numPoints) {
453: PetscCall(PetscPrintf(PETSC_COMM_SELF, " detJ: %g\n", (double)fegeom.detJ[0]));
454: #if !defined(PETSC_USE_COMPLEX)
455: PetscCall(DMPrintCellMatrix(e, "invJ", dE, dE, fegeom.invJ));
456: #endif
457: }
458: PetscCall(PetscFEEvaluateFieldJets_Internal(ds, Nf, 0, q, T, &fegeom, &coefficients[cOffset], PetscSafePointerPlusOffset(coefficients_t, cOffset), u, u_x, u_t));
459: if (dsAux) PetscCall(PetscFEEvaluateFieldJets_Internal(dsAux, NfAux, 0, q, TAux, &fegeom, &coefficientsAux[cOffsetAux], NULL, a, a_x, NULL));
460: for (i = 0; i < n0; ++i) f0_func[i](dE, 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]);
461: for (c = 0; c < T[field]->Nc; ++c) f0[q * T[field]->Nc + c] *= w;
462: for (i = 0; i < n1; ++i) f1_func[i](dE, 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 * dE]);
463: for (c = 0; c < T[field]->Nc; ++c)
464: for (d = 0; d < dE; ++d) f1[(q * T[field]->Nc + c) * dE + d] *= w;
465: if (debug) {
466: // LCOV_EXCL_START
467: PetscCall(PetscPrintf(PETSC_COMM_SELF, " quad point %" PetscInt_FMT " wt %g x:", q, (double)quadWeights[q]));
468: for (c = 0; c < dE; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %g", (double)fegeom.v[c]));
469: PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
470: if (debug > 2) {
471: PetscCall(PetscPrintf(PETSC_COMM_SELF, " field %" PetscInt_FMT ":", field));
472: for (c = 0; c < T[field]->Nc; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %g", (double)PetscRealPart(u[uOff[field] + c])));
473: PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
474: PetscCall(PetscPrintf(PETSC_COMM_SELF, " field der %" PetscInt_FMT ":", field));
475: for (c = 0; c < T[field]->Nc * dE; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %g", (double)PetscRealPart(u_x[uOff[field] + c])));
476: PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
477: PetscCall(PetscPrintf(PETSC_COMM_SELF, " resid %" PetscInt_FMT ":", field));
478: for (c = 0; c < T[field]->Nc; ++c) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %g", (double)PetscRealPart(f0[q * T[field]->Nc + c])));
479: PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
480: PetscCall(PetscPrintf(PETSC_COMM_SELF, " res der %" PetscInt_FMT ":", field));
481: for (c = 0; c < T[field]->Nc; ++c) {
482: for (d = 0; d < dE; ++d) PetscCall(PetscPrintf(PETSC_COMM_SELF, " %g", (double)PetscRealPart(f1[(q * T[field]->Nc + c) * dE + d])));
483: }
484: PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
485: }
486: // LCOV_EXCL_STOP
487: }
488: }
489: PetscCall(PetscFEUpdateElementVec_Internal(fe, T[field], 0, basisReal, basisDerReal, e, cgeom, f0, f1, &elemVec[cOffset + fOffset]));
490: cOffset += totDim;
491: cOffsetAux += totDimAux;
492: }
493: PetscFunctionReturn(PETSC_SUCCESS);
494: }
496: 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[])
497: {
498: const PetscInt debug = ds->printIntegrate;
499: const PetscInt field = key.field;
500: PetscFE fe;
501: PetscInt n0, n1, i;
502: PetscBdPointFunc *f0_func, *f1_func;
503: PetscQuadrature quad;
504: PetscTabulation *Tf, *TfAux = NULL;
505: PetscScalar *f0, *f1, *u, *u_t = NULL, *u_x, *a, *a_x, *basisReal, *basisDerReal;
506: const PetscScalar *constants;
507: PetscReal *x, cellScale;
508: PetscInt *uOff, *uOff_x, *aOff = NULL, *aOff_x = NULL;
509: PetscInt dim, dimAux, numConstants, Nf, NfAux = 0, totDim, totDimAux = 0, cOffset = 0, cOffsetAux = 0, fOffset, e, NcI;
510: PetscBool auxOnBd = PETSC_FALSE;
511: const PetscReal *quadPoints, *quadWeights;
512: PetscInt qdim, qNc, Nq, q, dE;
514: PetscFunctionBegin;
515: PetscCall(PetscDSGetDiscretization(ds, field, (PetscObject *)&fe));
516: PetscCall(PetscFEGetSpatialDimension(fe, &dim));
517: cellScale = (PetscReal)PetscPowInt(2, dim);
518: PetscCall(PetscFEGetFaceQuadrature(fe, &quad));
519: PetscCall(PetscDSGetNumFields(ds, &Nf));
520: PetscCall(PetscDSGetTotalDimension(ds, &totDim));
521: PetscCall(PetscDSGetComponentOffsets(ds, &uOff));
522: PetscCall(PetscDSGetComponentDerivativeOffsets(ds, &uOff_x));
523: PetscCall(PetscDSGetFieldOffset(ds, field, &fOffset));
524: PetscCall(PetscWeakFormGetBdResidual(wf, key.label, key.value, key.field, key.part, &n0, &f0_func, &n1, &f1_func));
525: if (!n0 && !n1) PetscFunctionReturn(PETSC_SUCCESS);
526: PetscCall(PetscDSGetEvaluationArrays(ds, &u, coefficients_t ? &u_t : NULL, &u_x));
527: PetscCall(PetscDSGetWorkspace(ds, &x, &basisReal, &basisDerReal, NULL, NULL));
528: PetscCall(PetscDSGetWeakFormArrays(ds, &f0, &f1, NULL, NULL, NULL, NULL));
529: PetscCall(PetscDSGetFaceTabulation(ds, &Tf));
530: PetscCall(PetscDSSetIntegrationParameters(ds, field, PETSC_DETERMINE));
531: PetscCall(PetscDSGetConstants(ds, &numConstants, &constants));
532: if (dsAux) {
533: PetscCall(PetscDSGetSpatialDimension(dsAux, &dimAux));
534: PetscCall(PetscDSGetNumFields(dsAux, &NfAux));
535: PetscCall(PetscDSGetTotalDimension(dsAux, &totDimAux));
536: PetscCall(PetscDSGetComponentOffsets(dsAux, &aOff));
537: PetscCall(PetscDSGetComponentDerivativeOffsets(dsAux, &aOff_x));
538: PetscCall(PetscDSGetEvaluationArrays(dsAux, &a, NULL, &a_x));
539: auxOnBd = dimAux < dim ? PETSC_TRUE : PETSC_FALSE;
540: if (auxOnBd) PetscCall(PetscDSGetTabulation(dsAux, &TfAux));
541: else PetscCall(PetscDSGetFaceTabulation(dsAux, &TfAux));
542: 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);
543: }
544: NcI = Tf[field]->Nc;
545: PetscCall(PetscQuadratureGetData(quad, &qdim, &qNc, &Nq, &quadPoints, &quadWeights));
546: PetscCheck(qNc == 1, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only supports scalar quadrature, not %" PetscInt_FMT " components", qNc);
547: dE = fgeom->dimEmbed;
548: /* TODO FIX THIS */
549: fgeom->dim = dim - 1;
550: PetscCheck(fgeom->dim == qdim, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "FEGeom dim %" PetscInt_FMT " != %" PetscInt_FMT " quadrature dim", fgeom->dim, qdim);
551: for (e = 0; e < Ne; ++e) {
552: PetscFEGeom fegeom, cgeom;
553: const PetscInt face = fgeom->face[e][0];
555: fegeom.v = x; /* Workspace */
556: PetscCall(PetscArrayzero(f0, Nq * NcI));
557: PetscCall(PetscArrayzero(f1, Nq * NcI * dE));
558: for (q = 0; q < Nq; ++q) {
559: PetscReal w;
560: PetscInt c, d;
562: PetscCall(PetscFEGeomGetPoint(fgeom, e, q, &quadPoints[q * fgeom->dim], &fegeom));
563: PetscCall(PetscFEGeomGetCellPoint(fgeom, e, q, &cgeom));
564: PetscCall(PetscDSSetCellParameters(ds, fegeom.detJ[0] * cellScale));
565: w = fegeom.detJ[0] * quadWeights[q];
566: if (debug > 1) {
567: if ((fgeom->isAffine && q == 0) || (!fgeom->isAffine)) {
568: PetscCall(PetscPrintf(PETSC_COMM_SELF, " detJ: %g\n", (double)fegeom.detJ[0]));
569: #if !defined(PETSC_USE_COMPLEX)
570: PetscCall(DMPrintCellMatrix(e, "invJ", dim, dim, fegeom.invJ));
571: PetscCall(DMPrintCellVector(e, "n", dim, fegeom.n));
572: #endif
573: }
574: }
575: PetscCall(PetscFEEvaluateFieldJets_Internal(ds, Nf, face, q, Tf, &cgeom, &coefficients[cOffset], PetscSafePointerPlusOffset(coefficients_t, cOffset), u, u_x, u_t));
576: if (dsAux) PetscCall(PetscFEEvaluateFieldJets_Internal(dsAux, NfAux, auxOnBd ? 0 : face, q, TfAux, &cgeom, &coefficientsAux[cOffsetAux], NULL, a, a_x, NULL));
577: for (i = 0; i < n0; ++i) f0_func[i](dE, 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]);
578: for (c = 0; c < NcI; ++c) f0[q * NcI + c] *= w;
579: for (i = 0; i < n1; ++i) f1_func[i](dE, 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 * dE]);
580: for (c = 0; c < NcI; ++c)
581: for (d = 0; d < dE; ++d) f1[(q * NcI + c) * dE + d] *= w;
582: if (debug) {
583: PetscCall(PetscPrintf(PETSC_COMM_SELF, " elem %" PetscInt_FMT " quad point %" PetscInt_FMT "\n", e, q));
584: for (c = 0; c < NcI; ++c) {
585: if (n0) PetscCall(PetscPrintf(PETSC_COMM_SELF, " f0[%" PetscInt_FMT "] %g\n", c, (double)PetscRealPart(f0[q * NcI + c])));
586: if (n1) {
587: 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])));
588: PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
589: }
590: }
591: }
592: }
593: PetscCall(PetscFEUpdateElementVec_Internal(fe, Tf[field], face, basisReal, basisDerReal, e, fgeom, f0, f1, &elemVec[cOffset + fOffset]));
594: cOffset += totDim;
595: cOffsetAux += totDimAux;
596: }
597: PetscFunctionReturn(PETSC_SUCCESS);
598: }
600: /*
601: BdIntegral: Operates completely in the embedding dimension. The trick is to have special "face quadrature" so we only integrate over the face, but
602: all transforms operate in the full space and are square.
604: HybridIntegral: The discretization is lower dimensional. That means the transforms are non-square.
605: 1) DMPlexGetCellFields() retrieves from the hybrid cell, so it gets fields from both faces
606: 2) We need to assume that the orientation is 0 for both
607: 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()
608: */
609: PETSC_INTERN PetscErrorCode PetscFEIntegrateHybridResidual_Basic(PetscDS ds, PetscDS dsIn, PetscFormKey key, PetscInt s, PetscInt Ne, PetscFEGeom *fgeom, const PetscScalar coefficients[], const PetscScalar coefficients_t[], PetscDS dsAux, const PetscScalar coefficientsAux[], PetscReal t, PetscScalar elemVec[])
610: {
611: const PetscInt debug = ds->printIntegrate;
612: const PetscInt field = key.field;
613: PetscFE fe;
614: PetscWeakForm wf;
615: PetscInt n0, n1, i;
616: PetscBdPointFunc *f0_func, *f1_func;
617: PetscQuadrature quad;
618: DMPolytopeType ct;
619: PetscTabulation *Tf, *TfIn, *TfAux = NULL;
620: PetscScalar *f0, *f1, *u, *u_t = NULL, *u_x, *a, *a_x, *basisReal, *basisDerReal;
621: const PetscScalar *constants;
622: PetscReal *x;
623: PetscInt *uOff, *uOff_x, *aOff = NULL, *aOff_x = NULL;
624: PetscInt dim, dimAux, numConstants, Nf, NfAux = 0, totDim, totDimIn, totDimAux = 0, cOffset = 0, cOffsetIn = 0, cOffsetAux = 0, fOffset, e, NcI, NcS;
625: PetscBool isCohesiveField, auxOnBd = PETSC_FALSE;
626: const PetscReal *quadPoints, *quadWeights;
627: PetscInt qdim, qNc, Nq, q, dE;
629: PetscFunctionBegin;
630: /* Hybrid discretization is posed directly on faces */
631: PetscCall(PetscDSGetDiscretization(ds, field, (PetscObject *)&fe));
632: PetscCall(PetscFEGetSpatialDimension(fe, &dim));
633: PetscCall(PetscFEGetQuadrature(fe, &quad));
634: PetscCall(PetscDSGetNumFields(ds, &Nf));
635: PetscCall(PetscDSGetTotalDimension(ds, &totDim));
636: PetscCall(PetscDSGetTotalDimension(dsIn, &totDimIn));
637: PetscCall(PetscDSGetComponentOffsetsCohesive(dsIn, 0, &uOff)); // Change 0 to s for one-sided offsets
638: PetscCall(PetscDSGetComponentDerivativeOffsetsCohesive(dsIn, s, &uOff_x));
639: PetscCall(PetscDSGetFieldOffsetCohesive(ds, field, &fOffset));
640: PetscCall(PetscDSGetWeakForm(ds, &wf));
641: PetscCall(PetscWeakFormGetBdResidual(wf, key.label, key.value, key.field, key.part, &n0, &f0_func, &n1, &f1_func));
642: if (!n0 && !n1) PetscFunctionReturn(PETSC_SUCCESS);
643: PetscCall(PetscDSGetEvaluationArrays(ds, &u, coefficients_t ? &u_t : NULL, &u_x));
644: PetscCall(PetscDSGetWorkspace(ds, &x, &basisReal, &basisDerReal, NULL, NULL));
645: PetscCall(PetscDSGetWeakFormArrays(ds, &f0, &f1, NULL, NULL, NULL, NULL));
646: /* NOTE This is a bulk tabulation because the DS is a face discretization */
647: PetscCall(PetscDSGetTabulation(ds, &Tf));
648: PetscCall(PetscDSGetFaceTabulation(dsIn, &TfIn));
649: PetscCall(PetscDSSetIntegrationParameters(ds, field, PETSC_DETERMINE));
650: PetscCall(PetscDSGetConstants(ds, &numConstants, &constants));
651: if (dsAux) {
652: PetscCall(PetscDSGetSpatialDimension(dsAux, &dimAux));
653: PetscCall(PetscDSGetNumFields(dsAux, &NfAux));
654: PetscCall(PetscDSGetTotalDimension(dsAux, &totDimAux));
655: PetscCall(PetscDSGetComponentOffsets(dsAux, &aOff));
656: PetscCall(PetscDSGetComponentDerivativeOffsets(dsAux, &aOff_x));
657: PetscCall(PetscDSGetEvaluationArrays(dsAux, &a, NULL, &a_x));
658: auxOnBd = dimAux == dim ? PETSC_TRUE : PETSC_FALSE;
659: if (auxOnBd) PetscCall(PetscDSGetTabulation(dsAux, &TfAux));
660: else PetscCall(PetscDSGetFaceTabulation(dsAux, &TfAux));
661: 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);
662: }
663: PetscCall(PetscDSGetCohesive(ds, field, &isCohesiveField));
664: NcI = Tf[field]->Nc;
665: NcS = NcI;
666: if (!isCohesiveField && s == 2) {
667: // If we are integrating over a cohesive cell (s = 2) for a non-cohesive fields, we use both sides
668: NcS *= 2;
669: }
670: PetscCall(PetscQuadratureGetData(quad, &qdim, &qNc, &Nq, &quadPoints, &quadWeights));
671: PetscCall(PetscQuadratureGetCellType(quad, &ct));
672: PetscCheck(qNc == 1, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only supports scalar quadrature, not %" PetscInt_FMT " components", qNc);
673: dE = fgeom->dimEmbed;
674: PetscCheck(fgeom->dim == qdim, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "FEGeom dim %" PetscInt_FMT " != %" PetscInt_FMT " quadrature dim", fgeom->dim, qdim);
675: for (e = 0; e < Ne; ++e) {
676: PetscFEGeom fegeom;
677: const PetscInt face[2] = {fgeom->face[e * 2 + 0][0], fgeom->face[e * 2 + 1][2]};
678: const PetscInt ornt[2] = {fgeom->face[e * 2 + 0][1], fgeom->face[e * 2 + 1][3]};
679: const PetscInt cornt[2] = {fgeom->face[e * 2 + 0][3], fgeom->face[e * 2 + 1][1]};
681: fegeom.v = x; /* Workspace */
682: PetscCall(PetscArrayzero(f0, Nq * NcS));
683: PetscCall(PetscArrayzero(f1, Nq * NcS * dE));
684: for (q = 0; q < Nq; ++q) {
685: PetscInt qpt[2];
686: PetscReal w;
687: PetscInt c, d;
689: PetscCall(PetscDSPermuteQuadPoint(ds, DMPolytopeTypeComposeOrientationInv(ct, cornt[0], ornt[0]), field, q, &qpt[0]));
690: PetscCall(PetscDSPermuteQuadPoint(ds, DMPolytopeTypeComposeOrientationInv(ct, ornt[1], cornt[1]), field, q, &qpt[1]));
691: PetscCall(PetscFEGeomGetPoint(fgeom, e * 2, q, &quadPoints[q * fgeom->dim], &fegeom));
692: w = fegeom.detJ[0] * quadWeights[q];
693: if (debug > 1 && q < fgeom->numPoints) {
694: PetscCall(PetscPrintf(PETSC_COMM_SELF, " detJ: %g\n", (double)fegeom.detJ[0]));
695: #if !defined(PETSC_USE_COMPLEX)
696: PetscCall(DMPrintCellMatrix(e, "invJ", dim, dE, fegeom.invJ));
697: #endif
698: }
699: if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, " quad point %" PetscInt_FMT " weight %g detJ %g\n", q, (double)quadWeights[q], (double)fegeom.detJ[0]));
700: /* TODO Is this cell or face quadrature, meaning should we use 'q' or 'face*Nq+q' */
701: PetscCall(PetscFEEvaluateFieldJets_Hybrid_Internal(ds, Nf, 0, q, Tf, face, qpt, TfIn, &fegeom, &coefficients[cOffsetIn], PetscSafePointerPlusOffset(coefficients_t, cOffsetIn), u, u_x, u_t));
702: if (dsAux) PetscCall(PetscFEEvaluateFieldJets_Internal(dsAux, NfAux, auxOnBd ? 0 : face[s], auxOnBd ? q : qpt[s], TfAux, &fegeom, &coefficientsAux[cOffsetAux], NULL, a, a_x, NULL));
703: for (i = 0; i < n0; ++i) f0_func[i](dE, 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]);
704: for (c = 0; c < NcS; ++c) f0[q * NcS + c] *= w;
705: for (i = 0; i < n1; ++i) f1_func[i](dE, 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]);
706: for (c = 0; c < NcS; ++c)
707: for (d = 0; d < dE; ++d) f1[(q * NcS + c) * dE + d] *= w;
708: }
709: if (isCohesiveField) {
710: PetscCall(PetscFEUpdateElementVec_Internal(fe, Tf[field], 0, basisReal, basisDerReal, e, fgeom, f0, f1, &elemVec[cOffset + fOffset]));
711: } else {
712: PetscCall(PetscFEUpdateElementVec_Hybrid_Internal(fe, Tf[field], 0, s, basisReal, basisDerReal, fgeom, f0, f1, &elemVec[cOffset + fOffset]));
713: }
714: cOffset += totDim;
715: cOffsetIn += totDimIn;
716: cOffsetAux += totDimAux;
717: }
718: PetscFunctionReturn(PETSC_SUCCESS);
719: }
721: 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[])
722: {
723: const PetscInt debug = ds->printIntegrate;
724: PetscFE feI, feJ;
725: PetscWeakForm wf;
726: PetscPointJac *g0_func, *g1_func, *g2_func, *g3_func;
727: PetscInt n0, n1, n2, n3, i;
728: PetscInt cOffset = 0; /* Offset into coefficients[] for element e */
729: PetscInt cOffsetAux = 0; /* Offset into coefficientsAux[] for element e */
730: PetscInt eOffset = 0; /* Offset into elemMat[] for element e */
731: PetscInt offsetI = 0; /* Offset into an element vector for fieldI */
732: PetscInt offsetJ = 0; /* Offset into an element vector for fieldJ */
733: PetscQuadrature quad;
734: PetscTabulation *T, *TAux = NULL;
735: PetscScalar *g0 = NULL, *g1 = NULL, *g2 = NULL, *g3 = NULL, *u, *u_t = NULL, *u_x, *a, *a_x, *basisReal, *basisDerReal, *testReal, *testDerReal;
736: const PetscScalar *constants;
737: PetscReal *x, cellScale;
738: PetscInt *uOff, *uOff_x, *aOff = NULL, *aOff_x = NULL;
739: PetscInt NcI = 0, NcJ = 0;
740: PetscInt dim, numConstants, Nf, fieldI, fieldJ, NfAux = 0, totDim, totDimAux = 0, e;
741: PetscInt dE, Np;
742: PetscBool isAffine;
743: const PetscReal *quadPoints, *quadWeights;
744: PetscInt qNc, Nq, q;
746: PetscFunctionBegin;
747: PetscCall(PetscDSGetNumFields(ds, &Nf));
748: fieldI = key.field / Nf;
749: fieldJ = key.field % Nf;
750: PetscCall(PetscDSGetDiscretization(ds, fieldI, (PetscObject *)&feI));
751: PetscCall(PetscDSGetDiscretization(ds, fieldJ, (PetscObject *)&feJ));
752: PetscCall(PetscFEGetSpatialDimension(feI, &dim));
753: cellScale = (PetscReal)PetscPowInt(2, dim);
754: PetscCall(PetscFEGetQuadrature(feI, &quad));
755: PetscCall(PetscDSGetTotalDimension(ds, &totDim));
756: PetscCall(PetscDSGetComponentOffsets(ds, &uOff));
757: PetscCall(PetscDSGetComponentDerivativeOffsets(ds, &uOff_x));
758: PetscCall(PetscDSGetWeakForm(ds, &wf));
759: switch (jtype) {
760: case PETSCFE_JACOBIAN_DYN:
761: PetscCall(PetscWeakFormGetDynamicJacobian(wf, key.label, key.value, fieldI, fieldJ, key.part, &n0, &g0_func, &n1, &g1_func, &n2, &g2_func, &n3, &g3_func));
762: break;
763: case PETSCFE_JACOBIAN_PRE:
764: PetscCall(PetscWeakFormGetJacobianPreconditioner(wf, key.label, key.value, fieldI, fieldJ, key.part, &n0, &g0_func, &n1, &g1_func, &n2, &g2_func, &n3, &g3_func));
765: break;
766: case PETSCFE_JACOBIAN:
767: PetscCall(PetscWeakFormGetJacobian(wf, key.label, key.value, fieldI, fieldJ, key.part, &n0, &g0_func, &n1, &g1_func, &n2, &g2_func, &n3, &g3_func));
768: break;
769: }
770: if (!n0 && !n1 && !n2 && !n3) PetscFunctionReturn(PETSC_SUCCESS);
771: PetscCall(PetscDSGetEvaluationArrays(ds, &u, coefficients_t ? &u_t : NULL, &u_x));
772: PetscCall(PetscDSGetWorkspace(ds, &x, &basisReal, &basisDerReal, &testReal, &testDerReal));
773: PetscCall(PetscDSGetWeakFormArrays(ds, NULL, NULL, n0 ? &g0 : NULL, n1 ? &g1 : NULL, n2 ? &g2 : NULL, n3 ? &g3 : NULL));
775: PetscCall(PetscDSGetTabulation(ds, &T));
776: PetscCall(PetscDSGetFieldOffset(ds, fieldI, &offsetI));
777: PetscCall(PetscDSGetFieldOffset(ds, fieldJ, &offsetJ));
778: PetscCall(PetscDSSetIntegrationParameters(ds, fieldI, fieldJ));
779: PetscCall(PetscDSGetConstants(ds, &numConstants, &constants));
780: if (dsAux) {
781: PetscCall(PetscDSGetNumFields(dsAux, &NfAux));
782: PetscCall(PetscDSGetTotalDimension(dsAux, &totDimAux));
783: PetscCall(PetscDSGetComponentOffsets(dsAux, &aOff));
784: PetscCall(PetscDSGetComponentDerivativeOffsets(dsAux, &aOff_x));
785: PetscCall(PetscDSGetEvaluationArrays(dsAux, &a, NULL, &a_x));
786: PetscCall(PetscDSGetTabulation(dsAux, &TAux));
787: 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);
788: }
789: NcI = T[fieldI]->Nc;
790: NcJ = T[fieldJ]->Nc;
791: Np = cgeom->numPoints;
792: dE = cgeom->dimEmbed;
793: isAffine = cgeom->isAffine;
794: PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights));
795: PetscCheck(qNc == 1, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only supports scalar quadrature, not %" PetscInt_FMT " components", qNc);
797: for (e = 0; e < Ne; ++e) {
798: PetscFEGeom fegeom;
800: fegeom.dim = cgeom->dim;
801: fegeom.dimEmbed = cgeom->dimEmbed;
802: fegeom.xi = NULL;
803: if (isAffine) {
804: fegeom.v = x;
805: fegeom.xi = cgeom->xi;
806: fegeom.J = &cgeom->J[e * Np * dE * dE];
807: fegeom.invJ = &cgeom->invJ[e * Np * dE * dE];
808: fegeom.detJ = &cgeom->detJ[e * Np];
809: }
810: for (q = 0; q < Nq; ++q) {
811: PetscReal w;
812: PetscInt c;
814: if (isAffine) {
815: CoordinatesRefToReal(dE, dim, fegeom.xi, &cgeom->v[e * Np * dE], fegeom.J, &quadPoints[q * dim], x);
816: } else {
817: fegeom.v = &cgeom->v[(e * Np + q) * dE];
818: fegeom.J = &cgeom->J[(e * Np + q) * dE * dE];
819: fegeom.invJ = &cgeom->invJ[(e * Np + q) * dE * dE];
820: fegeom.detJ = &cgeom->detJ[e * Np + q];
821: }
822: PetscCall(PetscDSSetCellParameters(ds, fegeom.detJ[0] * cellScale));
823: if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, " quad point %" PetscInt_FMT " weight %g detJ %g\n", q, (double)quadWeights[q], (double)fegeom.detJ[0]));
824: w = fegeom.detJ[0] * quadWeights[q];
825: if (coefficients) PetscCall(PetscFEEvaluateFieldJets_Internal(ds, Nf, 0, q, T, &fegeom, &coefficients[cOffset], PetscSafePointerPlusOffset(coefficients_t, cOffset), u, u_x, u_t));
826: if (dsAux) PetscCall(PetscFEEvaluateFieldJets_Internal(dsAux, NfAux, 0, q, TAux, &fegeom, &coefficientsAux[cOffsetAux], NULL, a, a_x, NULL));
827: if (n0) {
828: PetscCall(PetscArrayzero(g0, NcI * NcJ));
829: for (i = 0; i < n0; ++i) g0_func[i](dE, 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);
830: for (c = 0; c < NcI * NcJ; ++c) g0[c] *= w;
831: }
832: if (n1) {
833: PetscCall(PetscArrayzero(g1, NcI * NcJ * dE));
834: for (i = 0; i < n1; ++i) g1_func[i](dE, 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);
835: for (c = 0; c < NcI * NcJ * dE; ++c) g1[c] *= w;
836: }
837: if (n2) {
838: PetscCall(PetscArrayzero(g2, NcI * NcJ * dE));
839: for (i = 0; i < n2; ++i) g2_func[i](dE, 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);
840: for (c = 0; c < NcI * NcJ * dE; ++c) g2[c] *= w;
841: }
842: if (n3) {
843: PetscCall(PetscArrayzero(g3, NcI * NcJ * dE * dE));
844: for (i = 0; i < n3; ++i) g3_func[i](dE, 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);
845: for (c = 0; c < NcI * NcJ * dE * dE; ++c) g3[c] *= w;
846: }
848: PetscCall(PetscFEUpdateElementMat_Internal(feI, feJ, 0, q, T[fieldI], basisReal, basisDerReal, T[fieldJ], testReal, testDerReal, &fegeom, g0, g1, g2, g3, totDim, offsetI, offsetJ, elemMat + eOffset));
849: }
850: if (debug > 1) {
851: PetscInt f, g;
853: PetscCall(PetscPrintf(PETSC_COMM_SELF, "Element matrix for fields %" PetscInt_FMT " and %" PetscInt_FMT "\n", fieldI, fieldJ));
854: for (f = 0; f < T[fieldI]->Nb; ++f) {
855: const PetscInt i = offsetI + f;
856: for (g = 0; g < T[fieldJ]->Nb; ++g) {
857: const PetscInt j = offsetJ + g;
858: PetscCall(PetscPrintf(PETSC_COMM_SELF, " elemMat[%" PetscInt_FMT ", %" PetscInt_FMT "]: %g\n", f, g, (double)PetscRealPart(elemMat[eOffset + i * totDim + j])));
859: }
860: PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
861: }
862: }
863: cOffset += totDim;
864: cOffsetAux += totDimAux;
865: eOffset += PetscSqr(totDim);
866: }
867: PetscFunctionReturn(PETSC_SUCCESS);
868: }
870: PETSC_INTERN PetscErrorCode PetscFEIntegrateBdJacobian_Basic(PetscDS ds, PetscWeakForm wf, PetscFEJacobianType jtype, 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[])
871: {
872: const PetscInt debug = ds->printIntegrate;
873: PetscFE feI, feJ;
874: PetscBdPointJac *g0_func, *g1_func, *g2_func, *g3_func;
875: PetscInt n0, n1, n2, n3, i;
876: PetscInt cOffset = 0; /* Offset into coefficients[] for element e */
877: PetscInt cOffsetAux = 0; /* Offset into coefficientsAux[] for element e */
878: PetscInt eOffset = 0; /* Offset into elemMat[] for element e */
879: PetscInt offsetI = 0; /* Offset into an element vector for fieldI */
880: PetscInt offsetJ = 0; /* Offset into an element vector for fieldJ */
881: PetscQuadrature quad;
882: PetscTabulation *T, *TAux = NULL;
883: PetscScalar *g0, *g1, *g2, *g3, *u, *u_t = NULL, *u_x, *a, *a_x, *basisReal, *basisDerReal, *testReal, *testDerReal;
884: const PetscScalar *constants;
885: PetscReal *x, cellScale;
886: PetscInt *uOff, *uOff_x, *aOff = NULL, *aOff_x = NULL;
887: PetscInt NcI = 0, NcJ = 0;
888: PetscInt dim, numConstants, Nf, fieldI, fieldJ, NfAux = 0, totDim, totDimAux = 0, e;
889: PetscBool isAffine;
890: const PetscReal *quadPoints, *quadWeights;
891: PetscInt qNc, Nq, q, Np, dE;
893: PetscFunctionBegin;
894: PetscCall(PetscDSGetNumFields(ds, &Nf));
895: fieldI = key.field / Nf;
896: fieldJ = key.field % Nf;
897: PetscCall(PetscDSGetDiscretization(ds, fieldI, (PetscObject *)&feI));
898: PetscCall(PetscDSGetDiscretization(ds, fieldJ, (PetscObject *)&feJ));
899: PetscCall(PetscFEGetSpatialDimension(feI, &dim));
900: cellScale = (PetscReal)PetscPowInt(2, dim);
901: PetscCall(PetscFEGetFaceQuadrature(feI, &quad));
902: PetscCall(PetscDSGetTotalDimension(ds, &totDim));
903: PetscCall(PetscDSGetComponentOffsets(ds, &uOff));
904: PetscCall(PetscDSGetComponentDerivativeOffsets(ds, &uOff_x));
905: PetscCall(PetscDSGetFieldOffset(ds, fieldI, &offsetI));
906: PetscCall(PetscDSGetFieldOffset(ds, fieldJ, &offsetJ));
907: switch (jtype) {
908: case PETSCFE_JACOBIAN_PRE:
909: PetscCall(PetscWeakFormGetBdJacobianPreconditioner(wf, key.label, key.value, fieldI, fieldJ, key.part, &n0, &g0_func, &n1, &g1_func, &n2, &g2_func, &n3, &g3_func));
910: break;
911: case PETSCFE_JACOBIAN:
912: PetscCall(PetscWeakFormGetBdJacobian(wf, key.label, key.value, fieldI, fieldJ, key.part, &n0, &g0_func, &n1, &g1_func, &n2, &g2_func, &n3, &g3_func));
913: break;
914: case PETSCFE_JACOBIAN_DYN:
915: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "PETSCFE_JACOBIAN_DYN is not supported for PetscFEIntegrateBdJacobian()");
916: }
917: if (!n0 && !n1 && !n2 && !n3) PetscFunctionReturn(PETSC_SUCCESS);
918: PetscCall(PetscDSGetEvaluationArrays(ds, &u, coefficients_t ? &u_t : NULL, &u_x));
919: PetscCall(PetscDSGetWorkspace(ds, &x, &basisReal, &basisDerReal, &testReal, &testDerReal));
920: PetscCall(PetscDSGetWeakFormArrays(ds, NULL, NULL, &g0, &g1, &g2, &g3));
921: PetscCall(PetscDSGetFaceTabulation(ds, &T));
922: PetscCall(PetscDSSetIntegrationParameters(ds, fieldI, fieldJ));
923: PetscCall(PetscDSGetConstants(ds, &numConstants, &constants));
924: if (dsAux) {
925: PetscCall(PetscDSGetNumFields(dsAux, &NfAux));
926: PetscCall(PetscDSGetTotalDimension(dsAux, &totDimAux));
927: PetscCall(PetscDSGetComponentOffsets(dsAux, &aOff));
928: PetscCall(PetscDSGetComponentDerivativeOffsets(dsAux, &aOff_x));
929: PetscCall(PetscDSGetEvaluationArrays(dsAux, &a, NULL, &a_x));
930: PetscCall(PetscDSGetFaceTabulation(dsAux, &TAux));
931: }
932: NcI = T[fieldI]->Nc, NcJ = T[fieldJ]->Nc;
933: Np = fgeom->numPoints;
934: dE = fgeom->dimEmbed;
935: isAffine = fgeom->isAffine;
936: /* Initialize here in case the function is not defined */
937: PetscCall(PetscArrayzero(g0, NcI * NcJ));
938: PetscCall(PetscArrayzero(g1, NcI * NcJ * dE));
939: PetscCall(PetscArrayzero(g2, NcI * NcJ * dE));
940: PetscCall(PetscArrayzero(g3, NcI * NcJ * dE * dE));
941: PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights));
942: PetscCheck(qNc == 1, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only supports scalar quadrature, not %" PetscInt_FMT " components", qNc);
943: for (e = 0; e < Ne; ++e) {
944: PetscFEGeom fegeom, cgeom;
945: const PetscInt face = fgeom->face[e][0];
946: fegeom.n = NULL;
947: fegeom.v = NULL;
948: fegeom.xi = NULL;
949: fegeom.J = NULL;
950: fegeom.detJ = NULL;
951: fegeom.dim = fgeom->dim;
952: fegeom.dimEmbed = fgeom->dimEmbed;
953: cgeom.dim = fgeom->dim;
954: cgeom.dimEmbed = fgeom->dimEmbed;
955: if (isAffine) {
956: fegeom.v = x;
957: fegeom.xi = fgeom->xi;
958: fegeom.J = &fgeom->J[e * Np * dE * dE];
959: fegeom.invJ = &fgeom->invJ[e * Np * dE * dE];
960: fegeom.detJ = &fgeom->detJ[e * Np];
961: fegeom.n = &fgeom->n[e * Np * dE];
963: cgeom.J = &fgeom->suppJ[0][e * Np * dE * dE];
964: cgeom.invJ = &fgeom->suppInvJ[0][e * Np * dE * dE];
965: cgeom.detJ = &fgeom->suppDetJ[0][e * Np];
966: }
967: for (q = 0; q < Nq; ++q) {
968: PetscReal w;
969: PetscInt c;
971: if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, " quad point %" PetscInt_FMT "\n", q));
972: if (isAffine) {
973: CoordinatesRefToReal(dE, dim - 1, fegeom.xi, &fgeom->v[e * Np * dE], fegeom.J, &quadPoints[q * (dim - 1)], x);
974: } else {
975: fegeom.v = &fgeom->v[(e * Np + q) * dE];
976: fegeom.J = &fgeom->J[(e * Np + q) * dE * dE];
977: fegeom.invJ = &fgeom->invJ[(e * Np + q) * dE * dE];
978: fegeom.detJ = &fgeom->detJ[e * Np + q];
979: fegeom.n = &fgeom->n[(e * Np + q) * dE];
981: cgeom.J = &fgeom->suppJ[0][(e * Np + q) * dE * dE];
982: cgeom.invJ = &fgeom->suppInvJ[0][(e * Np + q) * dE * dE];
983: cgeom.detJ = &fgeom->suppDetJ[0][e * Np + q];
984: }
985: PetscCall(PetscDSSetCellParameters(ds, fegeom.detJ[0] * cellScale));
986: w = fegeom.detJ[0] * quadWeights[q];
987: if (coefficients) PetscCall(PetscFEEvaluateFieldJets_Internal(ds, Nf, face, q, T, &cgeom, &coefficients[cOffset], &coefficients_t[cOffset], u, u_x, u_t));
988: if (dsAux) PetscCall(PetscFEEvaluateFieldJets_Internal(dsAux, NfAux, face, q, TAux, &cgeom, &coefficientsAux[cOffsetAux], NULL, a, a_x, NULL));
989: if (n0) {
990: PetscCall(PetscArrayzero(g0, NcI * NcJ));
991: for (i = 0; i < n0; ++i) g0_func[i](dE, 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);
992: for (c = 0; c < NcI * NcJ; ++c) g0[c] *= w;
993: }
994: if (n1) {
995: PetscCall(PetscArrayzero(g1, NcI * NcJ * dE));
996: for (i = 0; i < n1; ++i) g1_func[i](dE, 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);
997: for (c = 0; c < NcI * NcJ * dim; ++c) g1[c] *= w;
998: }
999: if (n2) {
1000: PetscCall(PetscArrayzero(g2, NcI * NcJ * dE));
1001: for (i = 0; i < n2; ++i) g2_func[i](dE, 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);
1002: for (c = 0; c < NcI * NcJ * dim; ++c) g2[c] *= w;
1003: }
1004: if (n3) {
1005: PetscCall(PetscArrayzero(g3, NcI * NcJ * dE * dE));
1006: for (i = 0; i < n3; ++i) g3_func[i](dE, 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);
1007: for (c = 0; c < NcI * NcJ * dim * dim; ++c) g3[c] *= w;
1008: }
1010: PetscCall(PetscFEUpdateElementMat_Internal(feI, feJ, face, q, T[fieldI], basisReal, basisDerReal, T[fieldJ], testReal, testDerReal, &cgeom, g0, g1, g2, g3, totDim, offsetI, offsetJ, elemMat + eOffset));
1011: }
1012: if (debug > 1) {
1013: PetscInt fc, f, gc, g;
1015: PetscCall(PetscPrintf(PETSC_COMM_SELF, "Element matrix for fields %" PetscInt_FMT " and %" PetscInt_FMT "\n", fieldI, fieldJ));
1016: for (fc = 0; fc < T[fieldI]->Nc; ++fc) {
1017: for (f = 0; f < T[fieldI]->Nb; ++f) {
1018: const PetscInt i = offsetI + f * T[fieldI]->Nc + fc;
1019: for (gc = 0; gc < T[fieldJ]->Nc; ++gc) {
1020: for (g = 0; g < T[fieldJ]->Nb; ++g) {
1021: const PetscInt j = offsetJ + g * T[fieldJ]->Nc + gc;
1022: 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])));
1023: }
1024: }
1025: PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
1026: }
1027: }
1028: }
1029: cOffset += totDim;
1030: cOffsetAux += totDimAux;
1031: eOffset += PetscSqr(totDim);
1032: }
1033: PetscFunctionReturn(PETSC_SUCCESS);
1034: }
1036: PETSC_INTERN PetscErrorCode PetscFEIntegrateHybridJacobian_Basic(PetscDS ds, PetscDS dsIn, 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[])
1037: {
1038: const PetscInt debug = ds->printIntegrate;
1039: PetscFE feI, feJ;
1040: PetscWeakForm wf;
1041: PetscBdPointJac *g0_func, *g1_func, *g2_func, *g3_func;
1042: PetscInt n0, n1, n2, n3, i;
1043: PetscInt cOffset = 0; /* Offset into coefficients[] for element e */
1044: PetscInt cOffsetAux = 0; /* Offset into coefficientsAux[] for element e */
1045: PetscInt eOffset = 0; /* Offset into elemMat[] for element e */
1046: PetscInt offsetI = 0; /* Offset into an element vector for fieldI */
1047: PetscInt offsetJ = 0; /* Offset into an element vector for fieldJ */
1048: PetscQuadrature quad;
1049: DMPolytopeType ct;
1050: PetscTabulation *T, *TfIn, *TAux = NULL;
1051: PetscScalar *g0, *g1, *g2, *g3, *u, *u_t = NULL, *u_x, *a, *a_x, *basisReal, *basisDerReal, *testReal, *testDerReal;
1052: const PetscScalar *constants;
1053: PetscReal *x;
1054: PetscInt *uOff, *uOff_x, *aOff = NULL, *aOff_x = NULL;
1055: PetscInt NcI = 0, NcJ = 0, NcS, NcT;
1056: PetscInt dim, dimAux, numConstants, Nf, fieldI, fieldJ, NfAux = 0, totDim, totDimAux = 0, e;
1057: PetscBool isCohesiveFieldI, isCohesiveFieldJ, auxOnBd = PETSC_FALSE;
1058: const PetscReal *quadPoints, *quadWeights;
1059: PetscInt qNc, Nq, q;
1061: PetscFunctionBegin;
1062: PetscCall(PetscDSGetNumFields(ds, &Nf));
1063: fieldI = key.field / Nf;
1064: fieldJ = key.field % Nf;
1065: /* Hybrid discretization is posed directly on faces */
1066: PetscCall(PetscDSGetDiscretization(ds, fieldI, (PetscObject *)&feI));
1067: PetscCall(PetscDSGetDiscretization(ds, fieldJ, (PetscObject *)&feJ));
1068: PetscCall(PetscFEGetSpatialDimension(feI, &dim));
1069: PetscCall(PetscFEGetQuadrature(feI, &quad));
1070: PetscCall(PetscDSGetTotalDimension(ds, &totDim));
1071: PetscCall(PetscDSGetComponentOffsetsCohesive(ds, 0, &uOff)); // Change 0 to s for one-sided offsets
1072: PetscCall(PetscDSGetComponentDerivativeOffsetsCohesive(ds, s, &uOff_x));
1073: PetscCall(PetscDSGetWeakForm(ds, &wf));
1074: switch (jtype) {
1075: case PETSCFE_JACOBIAN_PRE:
1076: PetscCall(PetscWeakFormGetBdJacobianPreconditioner(wf, key.label, key.value, fieldI, fieldJ, key.part, &n0, &g0_func, &n1, &g1_func, &n2, &g2_func, &n3, &g3_func));
1077: break;
1078: case PETSCFE_JACOBIAN:
1079: PetscCall(PetscWeakFormGetBdJacobian(wf, key.label, key.value, fieldI, fieldJ, key.part, &n0, &g0_func, &n1, &g1_func, &n2, &g2_func, &n3, &g3_func));
1080: break;
1081: case PETSCFE_JACOBIAN_DYN:
1082: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No boundary hybrid Jacobians :)");
1083: }
1084: if (!n0 && !n1 && !n2 && !n3) PetscFunctionReturn(PETSC_SUCCESS);
1085: PetscCall(PetscDSGetEvaluationArrays(ds, &u, coefficients_t ? &u_t : NULL, &u_x));
1086: PetscCall(PetscDSGetWorkspace(ds, &x, &basisReal, &basisDerReal, &testReal, &testDerReal));
1087: PetscCall(PetscDSGetWeakFormArrays(ds, NULL, NULL, &g0, &g1, &g2, &g3));
1088: PetscCall(PetscDSGetTabulation(ds, &T));
1089: PetscCall(PetscDSGetFaceTabulation(dsIn, &TfIn));
1090: PetscCall(PetscDSGetFieldOffsetCohesive(ds, fieldI, &offsetI));
1091: PetscCall(PetscDSGetFieldOffsetCohesive(ds, fieldJ, &offsetJ));
1092: PetscCall(PetscDSSetIntegrationParameters(ds, fieldI, fieldJ));
1093: PetscCall(PetscDSGetConstants(ds, &numConstants, &constants));
1094: if (dsAux) {
1095: PetscCall(PetscDSGetSpatialDimension(dsAux, &dimAux));
1096: PetscCall(PetscDSGetNumFields(dsAux, &NfAux));
1097: PetscCall(PetscDSGetTotalDimension(dsAux, &totDimAux));
1098: PetscCall(PetscDSGetComponentOffsets(dsAux, &aOff));
1099: PetscCall(PetscDSGetComponentDerivativeOffsets(dsAux, &aOff_x));
1100: PetscCall(PetscDSGetEvaluationArrays(dsAux, &a, NULL, &a_x));
1101: auxOnBd = dimAux == dim ? PETSC_TRUE : PETSC_FALSE;
1102: if (auxOnBd) PetscCall(PetscDSGetTabulation(dsAux, &TAux));
1103: else PetscCall(PetscDSGetFaceTabulation(dsAux, &TAux));
1104: 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);
1105: }
1106: PetscCall(PetscDSGetCohesive(ds, fieldI, &isCohesiveFieldI));
1107: PetscCall(PetscDSGetCohesive(ds, fieldJ, &isCohesiveFieldJ));
1108: NcI = T[fieldI]->Nc;
1109: NcJ = T[fieldJ]->Nc;
1110: NcS = isCohesiveFieldI ? NcI : 2 * NcI;
1111: NcT = isCohesiveFieldJ ? NcJ : 2 * NcJ;
1112: if (!isCohesiveFieldI && s == 2) {
1113: // If we are integrating over a cohesive cell (s = 2) for a non-cohesive fields, we use both sides
1114: NcS *= 2;
1115: }
1116: if (!isCohesiveFieldJ && s == 2) {
1117: // If we are integrating over a cohesive cell (s = 2) for a non-cohesive fields, we use both sides
1118: NcT *= 2;
1119: }
1120: // The derivatives are constrained to be along the cell, so there are dim, not dE, components, even though
1121: // the coordinates are in dE dimensions
1122: PetscCall(PetscArrayzero(g0, NcS * NcT));
1123: PetscCall(PetscArrayzero(g1, NcS * NcT * dim));
1124: PetscCall(PetscArrayzero(g2, NcS * NcT * dim));
1125: PetscCall(PetscArrayzero(g3, NcS * NcT * dim * dim));
1126: PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights));
1127: PetscCall(PetscQuadratureGetCellType(quad, &ct));
1128: PetscCheck(qNc == 1, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only supports scalar quadrature, not %" PetscInt_FMT " components", qNc);
1129: for (e = 0; e < Ne; ++e) {
1130: PetscFEGeom fegeom;
1131: const PetscInt face[2] = {fgeom->face[e * 2 + 0][0], fgeom->face[e * 2 + 1][2]};
1132: const PetscInt ornt[2] = {fgeom->face[e * 2 + 0][1], fgeom->face[e * 2 + 1][3]};
1133: const PetscInt cornt[2] = {fgeom->face[e * 2 + 0][3], fgeom->face[e * 2 + 1][1]};
1135: fegeom.v = x; /* Workspace */
1136: for (q = 0; q < Nq; ++q) {
1137: PetscInt qpt[2];
1138: PetscReal w;
1139: PetscInt c;
1141: PetscCall(PetscDSPermuteQuadPoint(ds, DMPolytopeTypeComposeOrientationInv(ct, cornt[0], ornt[0]), fieldI, q, &qpt[0]));
1142: PetscCall(PetscDSPermuteQuadPoint(ds, DMPolytopeTypeComposeOrientationInv(ct, ornt[1], cornt[1]), fieldI, q, &qpt[1]));
1143: PetscCall(PetscFEGeomGetPoint(fgeom, e * 2, q, &quadPoints[q * fgeom->dim], &fegeom));
1144: w = fegeom.detJ[0] * quadWeights[q];
1145: if (debug > 1 && q < fgeom->numPoints) {
1146: PetscCall(PetscPrintf(PETSC_COMM_SELF, " detJ: %g\n", (double)fegeom.detJ[0]));
1147: #if !defined(PETSC_USE_COMPLEX)
1148: PetscCall(DMPrintCellMatrix(e, "invJ", dim, dim, fegeom.invJ));
1149: #endif
1150: }
1151: if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, " quad point %" PetscInt_FMT "\n", q));
1152: if (coefficients) PetscCall(PetscFEEvaluateFieldJets_Hybrid_Internal(ds, Nf, 0, q, T, face, qpt, TfIn, &fegeom, &coefficients[cOffset], PetscSafePointerPlusOffset(coefficients_t, cOffset), u, u_x, u_t));
1153: if (dsAux) PetscCall(PetscFEEvaluateFieldJets_Internal(dsAux, NfAux, auxOnBd ? 0 : face[s], auxOnBd ? q : qpt[s], TAux, &fegeom, &coefficientsAux[cOffsetAux], NULL, a, a_x, NULL));
1154: if (n0) {
1155: PetscCall(PetscArrayzero(g0, NcS * NcT));
1156: 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);
1157: for (c = 0; c < NcS * NcT; ++c) g0[c] *= w;
1158: }
1159: if (n1) {
1160: PetscCall(PetscArrayzero(g1, NcS * NcT * dim));
1161: 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);
1162: for (c = 0; c < NcS * NcT * dim; ++c) g1[c] *= w;
1163: }
1164: if (n2) {
1165: PetscCall(PetscArrayzero(g2, NcS * NcT * dim));
1166: 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);
1167: for (c = 0; c < NcS * NcT * dim; ++c) g2[c] *= w;
1168: }
1169: if (n3) {
1170: PetscCall(PetscArrayzero(g3, NcS * NcT * dim * dim));
1171: 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);
1172: for (c = 0; c < NcS * NcT * dim * dim; ++c) g3[c] *= w;
1173: }
1175: if (isCohesiveFieldI) {
1176: if (isCohesiveFieldJ) {
1177: PetscCall(PetscFEUpdateElementMat_Internal(feI, feJ, 0, q, T[fieldI], basisReal, basisDerReal, T[fieldJ], testReal, testDerReal, &fegeom, g0, g1, g2, g3, totDim, offsetI, offsetJ, elemMat + eOffset));
1178: } else {
1179: PetscCall(PetscFEUpdateElementMat_Hybrid_Internal(feI, isCohesiveFieldI, feJ, isCohesiveFieldJ, 0, 0, 0, q, T[fieldI], basisReal, basisDerReal, T[fieldJ], testReal, testDerReal, &fegeom, g0, g1, g2, g3, eOffset, totDim, offsetI, offsetJ, elemMat));
1180: PetscCall(PetscFEUpdateElementMat_Hybrid_Internal(feI, isCohesiveFieldI, feJ, isCohesiveFieldJ, 0, 1, 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));
1181: }
1182: } else {
1183: if (s == 2) {
1184: if (isCohesiveFieldJ) {
1185: PetscCall(PetscFEUpdateElementMat_Hybrid_Internal(feI, isCohesiveFieldI, feJ, isCohesiveFieldJ, 0, 0, 0, q, T[fieldI], basisReal, basisDerReal, T[fieldJ], testReal, testDerReal, &fegeom, g0, g1, g2, g3, eOffset, totDim, offsetI, offsetJ, elemMat));
1186: PetscCall(PetscFEUpdateElementMat_Hybrid_Internal(feI, isCohesiveFieldI, feJ, isCohesiveFieldJ, 0, 1, 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));
1187: } else {
1188: PetscCall(PetscFEUpdateElementMat_Hybrid_Internal(feI, isCohesiveFieldI, feJ, isCohesiveFieldJ, 0, 0, 0, q, T[fieldI], basisReal, basisDerReal, T[fieldJ], testReal, testDerReal, &fegeom, g0, g1, g2, g3, eOffset, totDim, offsetI, offsetJ, elemMat));
1189: PetscCall(PetscFEUpdateElementMat_Hybrid_Internal(feI, isCohesiveFieldI, feJ, isCohesiveFieldJ, 0, 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));
1190: PetscCall(PetscFEUpdateElementMat_Hybrid_Internal(feI, isCohesiveFieldI, feJ, isCohesiveFieldJ, 0, 1, 0, q, T[fieldI], basisReal, basisDerReal, T[fieldJ], testReal, testDerReal, &fegeom, &g0[NcI * NcJ * 2], &g1[NcI * NcJ * dim * 2], &g2[NcI * NcJ * dim * 2], &g3[NcI * NcJ * dim * dim * 2], eOffset, totDim, offsetI, offsetJ, elemMat));
1191: PetscCall(PetscFEUpdateElementMat_Hybrid_Internal(feI, isCohesiveFieldI, feJ, isCohesiveFieldJ, 0, 1, 1, q, T[fieldI], basisReal, basisDerReal, T[fieldJ], testReal, testDerReal, &fegeom, &g0[NcI * NcJ * 3], &g1[NcI * NcJ * dim * 3], &g2[NcI * NcJ * dim * 3], &g3[NcI * NcJ * dim * dim * 3], eOffset, totDim, offsetI, offsetJ, elemMat));
1192: }
1193: } else
1194: PetscCall(PetscFEUpdateElementMat_Hybrid_Internal(feI, isCohesiveFieldI, feJ, isCohesiveFieldJ, 0, s, s, q, T[fieldI], basisReal, basisDerReal, T[fieldJ], testReal, testDerReal, &fegeom, g0, g1, g2, g3, eOffset, totDim, offsetI, offsetJ, elemMat));
1195: }
1196: }
1197: if (debug > 1) {
1198: const PetscInt fS = 0 + (isCohesiveFieldI ? 0 : (s == 2 ? 0 : s * T[fieldI]->Nb));
1199: const PetscInt fE = T[fieldI]->Nb + (isCohesiveFieldI ? 0 : (s == 2 ? T[fieldI]->Nb : s * T[fieldI]->Nb));
1200: const PetscInt gS = 0 + (isCohesiveFieldJ ? 0 : (s == 2 ? 0 : s * T[fieldJ]->Nb));
1201: const PetscInt gE = T[fieldJ]->Nb + (isCohesiveFieldJ ? 0 : (s == 2 ? T[fieldJ]->Nb : s * T[fieldJ]->Nb));
1202: PetscInt f, g;
1204: PetscCall(PetscPrintf(PETSC_COMM_SELF, "Element matrix for fields %" PetscInt_FMT " and %" PetscInt_FMT " s %s totDim %" PetscInt_FMT " offsets (%" PetscInt_FMT ", %" PetscInt_FMT ", %" PetscInt_FMT ")\n", fieldI, fieldJ, s ? (s > 1 ? "Coh" : "Pos") : "Neg", totDim, eOffset, offsetI, offsetJ));
1205: for (f = fS; f < fE; ++f) {
1206: const PetscInt i = offsetI + f;
1207: for (g = gS; g < gE; ++g) {
1208: const PetscInt j = offsetJ + g;
1209: PetscCheck(i < totDim && j < totDim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Fuck up %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT " %" PetscInt_FMT, f, i, g, j);
1210: PetscCall(PetscPrintf(PETSC_COMM_SELF, " elemMat[%" PetscInt_FMT ",%" PetscInt_FMT ",%" PetscInt_FMT ",%" PetscInt_FMT "]: %g\n", f / NcI, f % NcI, g / NcJ, g % NcJ, (double)PetscRealPart(elemMat[eOffset + i * totDim + j])));
1211: }
1212: PetscCall(PetscPrintf(PETSC_COMM_SELF, "\n"));
1213: }
1214: }
1215: cOffset += totDim;
1216: cOffsetAux += totDimAux;
1217: eOffset += PetscSqr(totDim);
1218: }
1219: PetscFunctionReturn(PETSC_SUCCESS);
1220: }
1222: static PetscErrorCode PetscFEInitialize_Basic(PetscFE fem)
1223: {
1224: PetscFunctionBegin;
1225: fem->ops->setfromoptions = NULL;
1226: fem->ops->setup = PetscFESetUp_Basic;
1227: fem->ops->view = PetscFEView_Basic;
1228: fem->ops->destroy = PetscFEDestroy_Basic;
1229: fem->ops->getdimension = PetscFEGetDimension_Basic;
1230: fem->ops->computetabulation = PetscFEComputeTabulation_Basic;
1231: fem->ops->integrate = PetscFEIntegrate_Basic;
1232: fem->ops->integratebd = PetscFEIntegrateBd_Basic;
1233: fem->ops->integrateresidual = PetscFEIntegrateResidual_Basic;
1234: fem->ops->integratebdresidual = PetscFEIntegrateBdResidual_Basic;
1235: fem->ops->integratehybridresidual = PetscFEIntegrateHybridResidual_Basic;
1236: fem->ops->integratejacobianaction = NULL /* PetscFEIntegrateJacobianAction_Basic */;
1237: fem->ops->integratejacobian = PetscFEIntegrateJacobian_Basic;
1238: fem->ops->integratebdjacobian = PetscFEIntegrateBdJacobian_Basic;
1239: fem->ops->integratehybridjacobian = PetscFEIntegrateHybridJacobian_Basic;
1240: PetscFunctionReturn(PETSC_SUCCESS);
1241: }
1243: /*MC
1244: PETSCFEBASIC = "basic" - A `PetscFE` object that integrates with basic tiling and no vectorization
1246: Level: intermediate
1248: .seealso: `PetscFE`, `PetscFEType`, `PetscFECreate()`, `PetscFESetType()`
1249: M*/
1251: PETSC_EXTERN PetscErrorCode PetscFECreate_Basic(PetscFE fem)
1252: {
1253: PetscFE_Basic *b;
1255: PetscFunctionBegin;
1257: PetscCall(PetscNew(&b));
1258: fem->data = b;
1260: PetscCall(PetscFEInitialize_Basic(fem));
1261: PetscFunctionReturn(PETSC_SUCCESS);
1262: }