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