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