1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petscsf.h> 3 4 #include <petscblaslapack.h> 5 #include <petsc/private/hashsetij.h> 6 #include <petsc/private/petscfeimpl.h> 7 #include <petsc/private/petscfvimpl.h> 8 9 PetscBool Clementcite = PETSC_FALSE; 10 const char ClementCitation[] = "@article{clement1975approximation,\n" 11 " title = {Approximation by finite element functions using local regularization},\n" 12 " author = {Philippe Cl{\\'e}ment},\n" 13 " journal = {Revue fran{\\c{c}}aise d'automatique, informatique, recherche op{\\'e}rationnelle. Analyse num{\\'e}rique},\n" 14 " volume = {9},\n" 15 " number = {R2},\n" 16 " pages = {77--84},\n" 17 " year = {1975}\n}\n"; 18 19 static PetscErrorCode DMPlexConvertPlex(DM dm, DM *plex, PetscBool copy) 20 { 21 PetscBool isPlex; 22 23 PetscFunctionBegin; 24 PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMPLEX, &isPlex)); 25 if (isPlex) { 26 *plex = dm; 27 PetscCall(PetscObjectReference((PetscObject)dm)); 28 } else { 29 PetscCall(PetscObjectQuery((PetscObject)dm, "dm_plex", (PetscObject *)plex)); 30 if (!*plex) { 31 PetscCall(DMConvert(dm, DMPLEX, plex)); 32 PetscCall(PetscObjectCompose((PetscObject)dm, "dm_plex", (PetscObject)*plex)); 33 if (copy) { 34 DMSubDomainHookLink link; 35 36 PetscCall(DMCopyAuxiliaryVec(dm, *plex)); 37 /* Run the subdomain hook (this will copy the DMSNES/DMTS) */ 38 for (link = dm->subdomainhook; link; link = link->next) { 39 if (link->ddhook) PetscCall((*link->ddhook)(dm, *plex, link->ctx)); 40 } 41 } 42 } else { 43 PetscCall(PetscObjectReference((PetscObject)*plex)); 44 } 45 } 46 PetscFunctionReturn(PETSC_SUCCESS); 47 } 48 49 static PetscErrorCode PetscContainerUserDestroy_PetscFEGeom(void *ctx) 50 { 51 PetscFEGeom *geom = (PetscFEGeom *)ctx; 52 53 PetscFunctionBegin; 54 PetscCall(PetscFEGeomDestroy(&geom)); 55 PetscFunctionReturn(PETSC_SUCCESS); 56 } 57 58 static PetscErrorCode DMPlexGetFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom) 59 { 60 char composeStr[33] = {0}; 61 PetscObjectId id; 62 PetscContainer container; 63 64 PetscFunctionBegin; 65 PetscCall(PetscObjectGetId((PetscObject)quad, &id)); 66 PetscCall(PetscSNPrintf(composeStr, 32, "DMPlexGetFEGeom_%" PetscInt64_FMT "\n", id)); 67 PetscCall(PetscObjectQuery((PetscObject)pointIS, composeStr, (PetscObject *)&container)); 68 if (container) { 69 PetscCall(PetscContainerGetPointer(container, (void **)geom)); 70 } else { 71 PetscCall(DMFieldCreateFEGeom(coordField, pointIS, quad, faceData, geom)); 72 PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &container)); 73 PetscCall(PetscContainerSetPointer(container, (void *)*geom)); 74 PetscCall(PetscContainerSetUserDestroy(container, PetscContainerUserDestroy_PetscFEGeom)); 75 PetscCall(PetscObjectCompose((PetscObject)pointIS, composeStr, (PetscObject)container)); 76 PetscCall(PetscContainerDestroy(&container)); 77 } 78 PetscFunctionReturn(PETSC_SUCCESS); 79 } 80 81 static PetscErrorCode DMPlexRestoreFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom) 82 { 83 PetscFunctionBegin; 84 *geom = NULL; 85 PetscFunctionReturn(PETSC_SUCCESS); 86 } 87 88 /*@ 89 DMPlexGetScale - Get the scale for the specified fundamental unit 90 91 Not collective 92 93 Input Parameters: 94 + dm - the `DM` 95 - unit - The SI unit 96 97 Output Parameter: 98 . scale - The value used to scale all quantities with this unit 99 100 Level: advanced 101 102 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexSetScale()`, `PetscUnit` 103 @*/ 104 PetscErrorCode DMPlexGetScale(DM dm, PetscUnit unit, PetscReal *scale) 105 { 106 DM_Plex *mesh = (DM_Plex *)dm->data; 107 108 PetscFunctionBegin; 109 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 110 PetscValidRealPointer(scale, 3); 111 *scale = mesh->scale[unit]; 112 PetscFunctionReturn(PETSC_SUCCESS); 113 } 114 115 /*@ 116 DMPlexSetScale - Set the scale for the specified fundamental unit 117 118 Not collective 119 120 Input Parameters: 121 + dm - the `DM` 122 . unit - The SI unit 123 - scale - The value used to scale all quantities with this unit 124 125 Level: advanced 126 127 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetScale()`, `PetscUnit` 128 @*/ 129 PetscErrorCode DMPlexSetScale(DM dm, PetscUnit unit, PetscReal scale) 130 { 131 DM_Plex *mesh = (DM_Plex *)dm->data; 132 133 PetscFunctionBegin; 134 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 135 mesh->scale[unit] = scale; 136 PetscFunctionReturn(PETSC_SUCCESS); 137 } 138 139 static PetscErrorCode DMPlexProjectRigidBody_Private(PetscInt dim, PetscReal t, const PetscReal X[], PetscInt Nc, PetscScalar *mode, void *ctx) 140 { 141 const PetscInt eps[3][3][3] = { 142 {{0, 0, 0}, {0, 0, 1}, {0, -1, 0}}, 143 {{0, 0, -1}, {0, 0, 0}, {1, 0, 0} }, 144 {{0, 1, 0}, {-1, 0, 0}, {0, 0, 0} } 145 }; 146 PetscInt *ctxInt = (PetscInt *)ctx; 147 PetscInt dim2 = ctxInt[0]; 148 PetscInt d = ctxInt[1]; 149 PetscInt i, j, k = dim > 2 ? d - dim : d; 150 151 PetscFunctionBegin; 152 PetscCheck(dim == dim2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Input dimension %" PetscInt_FMT " does not match context dimension %" PetscInt_FMT, dim, dim2); 153 for (i = 0; i < dim; i++) mode[i] = 0.; 154 if (d < dim) { 155 mode[d] = 1.; /* Translation along axis d */ 156 } else { 157 for (i = 0; i < dim; i++) { 158 for (j = 0; j < dim; j++) { mode[j] += eps[i][j][k] * X[i]; /* Rotation about axis d */ } 159 } 160 } 161 PetscFunctionReturn(PETSC_SUCCESS); 162 } 163 164 /*@ 165 DMPlexCreateRigidBody - For the default global section, create rigid body modes by function space interpolation 166 167 Collective on dm 168 169 Input Parameters: 170 + dm - the `DM` 171 - field - The field number for the rigid body space, or 0 for the default 172 173 Output Parameter: 174 . sp - the null space 175 176 Level: advanced 177 178 Note: 179 This is necessary to provide a suitable coarse space for algebraic multigrid 180 181 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `MatNullSpaceCreate()`, `PCGAMG` 182 @*/ 183 PetscErrorCode DMPlexCreateRigidBody(DM dm, PetscInt field, MatNullSpace *sp) 184 { 185 PetscErrorCode (**func)(PetscInt, PetscReal, const PetscReal *, PetscInt, PetscScalar *, void *); 186 MPI_Comm comm; 187 Vec mode[6]; 188 PetscSection section, globalSection; 189 PetscInt dim, dimEmbed, Nf, n, m, mmin, d, i, j; 190 void **ctxs; 191 192 PetscFunctionBegin; 193 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 194 PetscCall(DMGetDimension(dm, &dim)); 195 PetscCall(DMGetCoordinateDim(dm, &dimEmbed)); 196 PetscCall(DMGetNumFields(dm, &Nf)); 197 PetscCheck(!Nf || !(field < 0 || field >= Nf), comm, PETSC_ERR_ARG_OUTOFRANGE, "Field %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", field, Nf); 198 if (dim == 1 && Nf < 2) { 199 PetscCall(MatNullSpaceCreate(comm, PETSC_TRUE, 0, NULL, sp)); 200 PetscFunctionReturn(PETSC_SUCCESS); 201 } 202 PetscCall(DMGetLocalSection(dm, §ion)); 203 PetscCall(DMGetGlobalSection(dm, &globalSection)); 204 PetscCall(PetscSectionGetConstrainedStorageSize(globalSection, &n)); 205 PetscCall(PetscCalloc2(Nf, &func, Nf, &ctxs)); 206 m = (dim * (dim + 1)) / 2; 207 PetscCall(VecCreate(comm, &mode[0])); 208 PetscCall(VecSetType(mode[0], dm->vectype)); 209 PetscCall(VecSetSizes(mode[0], n, PETSC_DETERMINE)); 210 PetscCall(VecSetUp(mode[0])); 211 PetscCall(VecGetSize(mode[0], &n)); 212 mmin = PetscMin(m, n); 213 func[field] = DMPlexProjectRigidBody_Private; 214 for (i = 1; i < m; ++i) PetscCall(VecDuplicate(mode[0], &mode[i])); 215 for (d = 0; d < m; d++) { 216 PetscInt ctx[2]; 217 218 ctxs[field] = (void *)(&ctx[0]); 219 ctx[0] = dimEmbed; 220 ctx[1] = d; 221 PetscCall(DMProjectFunction(dm, 0.0, func, ctxs, INSERT_VALUES, mode[d])); 222 } 223 /* Orthonormalize system */ 224 for (i = 0; i < mmin; ++i) { 225 PetscScalar dots[6]; 226 227 PetscCall(VecNormalize(mode[i], NULL)); 228 PetscCall(VecMDot(mode[i], mmin - i - 1, mode + i + 1, dots + i + 1)); 229 for (j = i + 1; j < mmin; ++j) { 230 dots[j] *= -1.0; 231 PetscCall(VecAXPY(mode[j], dots[j], mode[i])); 232 } 233 } 234 PetscCall(MatNullSpaceCreate(comm, PETSC_FALSE, mmin, mode, sp)); 235 for (i = 0; i < m; ++i) PetscCall(VecDestroy(&mode[i])); 236 PetscCall(PetscFree2(func, ctxs)); 237 PetscFunctionReturn(PETSC_SUCCESS); 238 } 239 240 /*@ 241 DMPlexCreateRigidBodies - For the default global section, create rigid body modes by function space interpolation 242 243 Collective on dm 244 245 Input Parameters: 246 + dm - the `DM` 247 . nb - The number of bodies 248 . label - The `DMLabel` marking each domain 249 . nids - The number of ids per body 250 - ids - An array of the label ids in sequence for each domain 251 252 Output Parameter: 253 . sp - the null space 254 255 Level: advanced 256 257 Note: 258 This is necessary to provide a suitable coarse space for algebraic multigrid 259 260 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `MatNullSpaceCreate()` 261 @*/ 262 PetscErrorCode DMPlexCreateRigidBodies(DM dm, PetscInt nb, DMLabel label, const PetscInt nids[], const PetscInt ids[], MatNullSpace *sp) 263 { 264 MPI_Comm comm; 265 PetscSection section, globalSection; 266 Vec *mode; 267 PetscScalar *dots; 268 PetscInt dim, dimEmbed, n, m, b, d, i, j, off; 269 270 PetscFunctionBegin; 271 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 272 PetscCall(DMGetDimension(dm, &dim)); 273 PetscCall(DMGetCoordinateDim(dm, &dimEmbed)); 274 PetscCall(DMGetLocalSection(dm, §ion)); 275 PetscCall(DMGetGlobalSection(dm, &globalSection)); 276 PetscCall(PetscSectionGetConstrainedStorageSize(globalSection, &n)); 277 m = nb * (dim * (dim + 1)) / 2; 278 PetscCall(PetscMalloc2(m, &mode, m, &dots)); 279 PetscCall(VecCreate(comm, &mode[0])); 280 PetscCall(VecSetSizes(mode[0], n, PETSC_DETERMINE)); 281 PetscCall(VecSetUp(mode[0])); 282 for (i = 1; i < m; ++i) PetscCall(VecDuplicate(mode[0], &mode[i])); 283 for (b = 0, off = 0; b < nb; ++b) { 284 for (d = 0; d < m / nb; ++d) { 285 PetscInt ctx[2]; 286 PetscErrorCode (*func)(PetscInt, PetscReal, const PetscReal *, PetscInt, PetscScalar *, void *) = DMPlexProjectRigidBody_Private; 287 void *voidctx = (void *)(&ctx[0]); 288 289 ctx[0] = dimEmbed; 290 ctx[1] = d; 291 PetscCall(DMProjectFunctionLabel(dm, 0.0, label, nids[b], &ids[off], 0, NULL, &func, &voidctx, INSERT_VALUES, mode[d])); 292 off += nids[b]; 293 } 294 } 295 /* Orthonormalize system */ 296 for (i = 0; i < m; ++i) { 297 PetscScalar dots[6]; 298 299 PetscCall(VecNormalize(mode[i], NULL)); 300 PetscCall(VecMDot(mode[i], m - i - 1, mode + i + 1, dots + i + 1)); 301 for (j = i + 1; j < m; ++j) { 302 dots[j] *= -1.0; 303 PetscCall(VecAXPY(mode[j], dots[j], mode[i])); 304 } 305 } 306 PetscCall(MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp)); 307 for (i = 0; i < m; ++i) PetscCall(VecDestroy(&mode[i])); 308 PetscCall(PetscFree2(mode, dots)); 309 PetscFunctionReturn(PETSC_SUCCESS); 310 } 311 312 /*@ 313 DMPlexSetMaxProjectionHeight - In DMPlexProjectXXXLocal() functions, the projected values of a basis function's dofs 314 are computed by associating the basis function with one of the mesh points in its transitively-closed support, and 315 evaluating the dual space basis of that point. A basis function is associated with the point in its 316 transitively-closed support whose mesh height is highest (w.r.t. DAG height), but not greater than the maximum 317 projection height, which is set with this function. By default, the maximum projection height is zero, which means 318 that only mesh cells are used to project basis functions. A height of one, for example, evaluates a cell-interior 319 basis functions using its cells dual space basis, but all other basis functions with the dual space basis of a face. 320 321 Input Parameters: 322 + dm - the `DMPLEX` object 323 - height - the maximum projection height >= 0 324 325 Level: advanced 326 327 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetMaxProjectionHeight()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabelLocal()` 328 @*/ 329 PetscErrorCode DMPlexSetMaxProjectionHeight(DM dm, PetscInt height) 330 { 331 DM_Plex *plex = (DM_Plex *)dm->data; 332 333 PetscFunctionBegin; 334 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 335 plex->maxProjectionHeight = height; 336 PetscFunctionReturn(PETSC_SUCCESS); 337 } 338 339 /*@ 340 DMPlexGetMaxProjectionHeight - Get the maximum height (w.r.t. DAG) of mesh points used to evaluate dual bases in 341 DMPlexProjectXXXLocal() functions. 342 343 Input Parameters: 344 . dm - the `DMPLEX` object 345 346 Output Parameters: 347 . height - the maximum projection height 348 349 Level: intermediate 350 351 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexSetMaxProjectionHeight()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabelLocal()` 352 @*/ 353 PetscErrorCode DMPlexGetMaxProjectionHeight(DM dm, PetscInt *height) 354 { 355 DM_Plex *plex = (DM_Plex *)dm->data; 356 357 PetscFunctionBegin; 358 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 359 *height = plex->maxProjectionHeight; 360 PetscFunctionReturn(PETSC_SUCCESS); 361 } 362 363 typedef struct { 364 PetscReal alpha; /* The first Euler angle, and in 2D the only one */ 365 PetscReal beta; /* The second Euler angle */ 366 PetscReal gamma; /* The third Euler angle */ 367 PetscInt dim; /* The dimension of R */ 368 PetscScalar *R; /* The rotation matrix, transforming a vector in the local basis to the global basis */ 369 PetscScalar *RT; /* The transposed rotation matrix, transforming a vector in the global basis to the local basis */ 370 } RotCtx; 371 372 /* 373 Note: Following https://en.wikipedia.org/wiki/Euler_angles, we will specify Euler angles by extrinsic rotations, meaning that 374 we rotate with respect to a fixed initial coordinate system, the local basis (x-y-z). The global basis (X-Y-Z) is reached as follows: 375 $ The XYZ system rotates about the z axis by alpha. The X axis is now at angle alpha with respect to the x axis. 376 $ The XYZ system rotates again about the x axis by beta. The Z axis is now at angle beta with respect to the z axis. 377 $ The XYZ system rotates a third time about the z axis by gamma. 378 */ 379 static PetscErrorCode DMPlexBasisTransformSetUp_Rotation_Internal(DM dm, void *ctx) 380 { 381 RotCtx *rc = (RotCtx *)ctx; 382 PetscInt dim = rc->dim; 383 PetscReal c1, s1, c2, s2, c3, s3; 384 385 PetscFunctionBegin; 386 PetscCall(PetscMalloc2(PetscSqr(dim), &rc->R, PetscSqr(dim), &rc->RT)); 387 switch (dim) { 388 case 2: 389 c1 = PetscCosReal(rc->alpha); 390 s1 = PetscSinReal(rc->alpha); 391 rc->R[0] = c1; 392 rc->R[1] = s1; 393 rc->R[2] = -s1; 394 rc->R[3] = c1; 395 PetscCall(PetscArraycpy(rc->RT, rc->R, PetscSqr(dim))); 396 DMPlex_Transpose2D_Internal(rc->RT); 397 break; 398 case 3: 399 c1 = PetscCosReal(rc->alpha); 400 s1 = PetscSinReal(rc->alpha); 401 c2 = PetscCosReal(rc->beta); 402 s2 = PetscSinReal(rc->beta); 403 c3 = PetscCosReal(rc->gamma); 404 s3 = PetscSinReal(rc->gamma); 405 rc->R[0] = c1 * c3 - c2 * s1 * s3; 406 rc->R[1] = c3 * s1 + c1 * c2 * s3; 407 rc->R[2] = s2 * s3; 408 rc->R[3] = -c1 * s3 - c2 * c3 * s1; 409 rc->R[4] = c1 * c2 * c3 - s1 * s3; 410 rc->R[5] = c3 * s2; 411 rc->R[6] = s1 * s2; 412 rc->R[7] = -c1 * s2; 413 rc->R[8] = c2; 414 PetscCall(PetscArraycpy(rc->RT, rc->R, PetscSqr(dim))); 415 DMPlex_Transpose3D_Internal(rc->RT); 416 break; 417 default: 418 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Dimension %" PetscInt_FMT " not supported", dim); 419 } 420 PetscFunctionReturn(PETSC_SUCCESS); 421 } 422 423 static PetscErrorCode DMPlexBasisTransformDestroy_Rotation_Internal(DM dm, void *ctx) 424 { 425 RotCtx *rc = (RotCtx *)ctx; 426 427 PetscFunctionBegin; 428 PetscCall(PetscFree2(rc->R, rc->RT)); 429 PetscCall(PetscFree(rc)); 430 PetscFunctionReturn(PETSC_SUCCESS); 431 } 432 433 static PetscErrorCode DMPlexBasisTransformGetMatrix_Rotation_Internal(DM dm, const PetscReal x[], PetscBool l2g, const PetscScalar **A, void *ctx) 434 { 435 RotCtx *rc = (RotCtx *)ctx; 436 437 PetscFunctionBeginHot; 438 PetscValidPointer(ctx, 5); 439 if (l2g) { 440 *A = rc->R; 441 } else { 442 *A = rc->RT; 443 } 444 PetscFunctionReturn(PETSC_SUCCESS); 445 } 446 447 PetscErrorCode DMPlexBasisTransformApplyReal_Internal(DM dm, const PetscReal x[], PetscBool l2g, PetscInt dim, const PetscReal *y, PetscReal *z, void *ctx) 448 { 449 PetscFunctionBegin; 450 #if defined(PETSC_USE_COMPLEX) 451 switch (dim) { 452 case 2: { 453 PetscScalar yt[2] = {y[0], y[1]}, zt[2] = {0.0, 0.0}; 454 455 PetscCall(DMPlexBasisTransformApply_Internal(dm, x, l2g, dim, yt, zt, ctx)); 456 z[0] = PetscRealPart(zt[0]); 457 z[1] = PetscRealPart(zt[1]); 458 } break; 459 case 3: { 460 PetscScalar yt[3] = {y[0], y[1], y[2]}, zt[3] = {0.0, 0.0, 0.0}; 461 462 PetscCall(DMPlexBasisTransformApply_Internal(dm, x, l2g, dim, yt, zt, ctx)); 463 z[0] = PetscRealPart(zt[0]); 464 z[1] = PetscRealPart(zt[1]); 465 z[2] = PetscRealPart(zt[2]); 466 } break; 467 } 468 #else 469 PetscCall(DMPlexBasisTransformApply_Internal(dm, x, l2g, dim, y, z, ctx)); 470 #endif 471 PetscFunctionReturn(PETSC_SUCCESS); 472 } 473 474 PetscErrorCode DMPlexBasisTransformApply_Internal(DM dm, const PetscReal x[], PetscBool l2g, PetscInt dim, const PetscScalar *y, PetscScalar *z, void *ctx) 475 { 476 const PetscScalar *A; 477 478 PetscFunctionBeginHot; 479 PetscCall((*dm->transformGetMatrix)(dm, x, l2g, &A, ctx)); 480 switch (dim) { 481 case 2: 482 DMPlex_Mult2D_Internal(A, 1, y, z); 483 break; 484 case 3: 485 DMPlex_Mult3D_Internal(A, 1, y, z); 486 break; 487 } 488 PetscFunctionReturn(PETSC_SUCCESS); 489 } 490 491 static PetscErrorCode DMPlexBasisTransformField_Internal(DM dm, DM tdm, Vec tv, PetscInt p, PetscInt f, PetscBool l2g, PetscScalar *a) 492 { 493 PetscSection ts; 494 const PetscScalar *ta, *tva; 495 PetscInt dof; 496 497 PetscFunctionBeginHot; 498 PetscCall(DMGetLocalSection(tdm, &ts)); 499 PetscCall(PetscSectionGetFieldDof(ts, p, f, &dof)); 500 PetscCall(VecGetArrayRead(tv, &ta)); 501 PetscCall(DMPlexPointLocalFieldRead(tdm, p, f, ta, &tva)); 502 if (l2g) { 503 switch (dof) { 504 case 4: 505 DMPlex_Mult2D_Internal(tva, 1, a, a); 506 break; 507 case 9: 508 DMPlex_Mult3D_Internal(tva, 1, a, a); 509 break; 510 } 511 } else { 512 switch (dof) { 513 case 4: 514 DMPlex_MultTranspose2D_Internal(tva, 1, a, a); 515 break; 516 case 9: 517 DMPlex_MultTranspose3D_Internal(tva, 1, a, a); 518 break; 519 } 520 } 521 PetscCall(VecRestoreArrayRead(tv, &ta)); 522 PetscFunctionReturn(PETSC_SUCCESS); 523 } 524 525 static PetscErrorCode DMPlexBasisTransformFieldTensor_Internal(DM dm, DM tdm, Vec tv, PetscInt pf, PetscInt f, PetscInt pg, PetscInt g, PetscBool l2g, PetscInt lda, PetscScalar *a) 526 { 527 PetscSection s, ts; 528 const PetscScalar *ta, *tvaf, *tvag; 529 PetscInt fdof, gdof, fpdof, gpdof; 530 531 PetscFunctionBeginHot; 532 PetscCall(DMGetLocalSection(dm, &s)); 533 PetscCall(DMGetLocalSection(tdm, &ts)); 534 PetscCall(PetscSectionGetFieldDof(s, pf, f, &fpdof)); 535 PetscCall(PetscSectionGetFieldDof(s, pg, g, &gpdof)); 536 PetscCall(PetscSectionGetFieldDof(ts, pf, f, &fdof)); 537 PetscCall(PetscSectionGetFieldDof(ts, pg, g, &gdof)); 538 PetscCall(VecGetArrayRead(tv, &ta)); 539 PetscCall(DMPlexPointLocalFieldRead(tdm, pf, f, ta, &tvaf)); 540 PetscCall(DMPlexPointLocalFieldRead(tdm, pg, g, ta, &tvag)); 541 if (l2g) { 542 switch (fdof) { 543 case 4: 544 DMPlex_MatMult2D_Internal(tvaf, gpdof, lda, a, a); 545 break; 546 case 9: 547 DMPlex_MatMult3D_Internal(tvaf, gpdof, lda, a, a); 548 break; 549 } 550 switch (gdof) { 551 case 4: 552 DMPlex_MatMultTransposeLeft2D_Internal(tvag, fpdof, lda, a, a); 553 break; 554 case 9: 555 DMPlex_MatMultTransposeLeft3D_Internal(tvag, fpdof, lda, a, a); 556 break; 557 } 558 } else { 559 switch (fdof) { 560 case 4: 561 DMPlex_MatMultTranspose2D_Internal(tvaf, gpdof, lda, a, a); 562 break; 563 case 9: 564 DMPlex_MatMultTranspose3D_Internal(tvaf, gpdof, lda, a, a); 565 break; 566 } 567 switch (gdof) { 568 case 4: 569 DMPlex_MatMultLeft2D_Internal(tvag, fpdof, lda, a, a); 570 break; 571 case 9: 572 DMPlex_MatMultLeft3D_Internal(tvag, fpdof, lda, a, a); 573 break; 574 } 575 } 576 PetscCall(VecRestoreArrayRead(tv, &ta)); 577 PetscFunctionReturn(PETSC_SUCCESS); 578 } 579 580 PetscErrorCode DMPlexBasisTransformPoint_Internal(DM dm, DM tdm, Vec tv, PetscInt p, PetscBool fieldActive[], PetscBool l2g, PetscScalar *a) 581 { 582 PetscSection s; 583 PetscSection clSection; 584 IS clPoints; 585 const PetscInt *clp; 586 PetscInt *points = NULL; 587 PetscInt Nf, f, Np, cp, dof, d = 0; 588 589 PetscFunctionBegin; 590 PetscCall(DMGetLocalSection(dm, &s)); 591 PetscCall(PetscSectionGetNumFields(s, &Nf)); 592 PetscCall(DMPlexGetCompressedClosure(dm, s, p, &Np, &points, &clSection, &clPoints, &clp)); 593 for (f = 0; f < Nf; ++f) { 594 for (cp = 0; cp < Np * 2; cp += 2) { 595 PetscCall(PetscSectionGetFieldDof(s, points[cp], f, &dof)); 596 if (!dof) continue; 597 if (fieldActive[f]) PetscCall(DMPlexBasisTransformField_Internal(dm, tdm, tv, points[cp], f, l2g, &a[d])); 598 d += dof; 599 } 600 } 601 PetscCall(DMPlexRestoreCompressedClosure(dm, s, p, &Np, &points, &clSection, &clPoints, &clp)); 602 PetscFunctionReturn(PETSC_SUCCESS); 603 } 604 605 PetscErrorCode DMPlexBasisTransformPointTensor_Internal(DM dm, DM tdm, Vec tv, PetscInt p, PetscBool l2g, PetscInt lda, PetscScalar *a) 606 { 607 PetscSection s; 608 PetscSection clSection; 609 IS clPoints; 610 const PetscInt *clp; 611 PetscInt *points = NULL; 612 PetscInt Nf, f, g, Np, cpf, cpg, fdof, gdof, r, c = 0; 613 614 PetscFunctionBegin; 615 PetscCall(DMGetLocalSection(dm, &s)); 616 PetscCall(PetscSectionGetNumFields(s, &Nf)); 617 PetscCall(DMPlexGetCompressedClosure(dm, s, p, &Np, &points, &clSection, &clPoints, &clp)); 618 for (f = 0, r = 0; f < Nf; ++f) { 619 for (cpf = 0; cpf < Np * 2; cpf += 2) { 620 PetscCall(PetscSectionGetFieldDof(s, points[cpf], f, &fdof)); 621 for (g = 0, c = 0; g < Nf; ++g) { 622 for (cpg = 0; cpg < Np * 2; cpg += 2) { 623 PetscCall(PetscSectionGetFieldDof(s, points[cpg], g, &gdof)); 624 PetscCall(DMPlexBasisTransformFieldTensor_Internal(dm, tdm, tv, points[cpf], f, points[cpg], g, l2g, lda, &a[r * lda + c])); 625 c += gdof; 626 } 627 } 628 PetscCheck(c == lda, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of columns %" PetscInt_FMT " should be %" PetscInt_FMT, c, lda); 629 r += fdof; 630 } 631 } 632 PetscCheck(r == lda, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of rows %" PetscInt_FMT " should be %" PetscInt_FMT, c, lda); 633 PetscCall(DMPlexRestoreCompressedClosure(dm, s, p, &Np, &points, &clSection, &clPoints, &clp)); 634 PetscFunctionReturn(PETSC_SUCCESS); 635 } 636 637 static PetscErrorCode DMPlexBasisTransform_Internal(DM dm, Vec lv, PetscBool l2g) 638 { 639 DM tdm; 640 Vec tv; 641 PetscSection ts, s; 642 const PetscScalar *ta; 643 PetscScalar *a, *va; 644 PetscInt pStart, pEnd, p, Nf, f; 645 646 PetscFunctionBegin; 647 PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm)); 648 PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 649 PetscCall(DMGetLocalSection(tdm, &ts)); 650 PetscCall(DMGetLocalSection(dm, &s)); 651 PetscCall(PetscSectionGetChart(s, &pStart, &pEnd)); 652 PetscCall(PetscSectionGetNumFields(s, &Nf)); 653 PetscCall(VecGetArray(lv, &a)); 654 PetscCall(VecGetArrayRead(tv, &ta)); 655 for (p = pStart; p < pEnd; ++p) { 656 for (f = 0; f < Nf; ++f) { 657 PetscCall(DMPlexPointLocalFieldRef(dm, p, f, a, &va)); 658 PetscCall(DMPlexBasisTransformField_Internal(dm, tdm, tv, p, f, l2g, va)); 659 } 660 } 661 PetscCall(VecRestoreArray(lv, &a)); 662 PetscCall(VecRestoreArrayRead(tv, &ta)); 663 PetscFunctionReturn(PETSC_SUCCESS); 664 } 665 666 /*@ 667 DMPlexGlobalToLocalBasis - Transform the values in the given local vector from the global basis to the local basis 668 669 Input Parameters: 670 + dm - The `DM` 671 - lv - A local vector with values in the global basis 672 673 Output Parameters: 674 . lv - A local vector with values in the local basis 675 676 Level: developer 677 678 Note: 679 This method is only intended to be called inside `DMGlobalToLocal()`. It is unlikely that a user will have a local vector full of coefficients for the global basis unless they are reimplementing GlobalToLocal. 680 681 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexLocalToGlobalBasis()`, `DMGetLocalSection()`, `DMPlexCreateBasisRotation()` 682 @*/ 683 PetscErrorCode DMPlexGlobalToLocalBasis(DM dm, Vec lv) 684 { 685 PetscFunctionBegin; 686 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 687 PetscValidHeaderSpecific(lv, VEC_CLASSID, 2); 688 PetscCall(DMPlexBasisTransform_Internal(dm, lv, PETSC_FALSE)); 689 PetscFunctionReturn(PETSC_SUCCESS); 690 } 691 692 /*@ 693 DMPlexLocalToGlobalBasis - Transform the values in the given local vector from the local basis to the global basis 694 695 Input Parameters: 696 + dm - The `DM` 697 - lv - A local vector with values in the local basis 698 699 Output Parameters: 700 . lv - A local vector with values in the global basis 701 702 Level: developer 703 704 Note: 705 This method is only intended to be called inside `DMGlobalToLocal()`. It is unlikely that a user would want a local vector full of coefficients for the global basis unless they are reimplementing GlobalToLocal. 706 707 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGlobalToLocalBasis()`, `DMGetLocalSection()`, `DMPlexCreateBasisRotation()` 708 @*/ 709 PetscErrorCode DMPlexLocalToGlobalBasis(DM dm, Vec lv) 710 { 711 PetscFunctionBegin; 712 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 713 PetscValidHeaderSpecific(lv, VEC_CLASSID, 2); 714 PetscCall(DMPlexBasisTransform_Internal(dm, lv, PETSC_TRUE)); 715 PetscFunctionReturn(PETSC_SUCCESS); 716 } 717 718 /*@ 719 DMPlexCreateBasisRotation - Create an internal transformation from the global basis, used to specify boundary conditions 720 and global solutions, to a local basis, appropriate for discretization integrals and assembly. 721 722 Input Parameters: 723 + dm - The `DM` 724 . alpha - The first Euler angle, and in 2D the only one 725 . beta - The second Euler angle 726 - gamma - The third Euler angle 727 728 Level: developer 729 730 Note: 731 Following https://en.wikipedia.org/wiki/Euler_angles, we will specify Euler angles by extrinsic rotations, meaning that 732 we rotate with respect to a fixed initial coordinate system, the local basis (x-y-z). The global basis (X-Y-Z) is reached as follows 733 .vb 734 The XYZ system rotates about the z axis by alpha. The X axis is now at angle alpha with respect to the x axis. 735 The XYZ system rotates again about the x axis by beta. The Z axis is now at angle beta with respect to the z axis. 736 The XYZ system rotates a third time about the z axis by gamma. 737 .ve 738 739 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGlobalToLocalBasis()`, `DMPlexLocalToGlobalBasis()` 740 @*/ 741 PetscErrorCode DMPlexCreateBasisRotation(DM dm, PetscReal alpha, PetscReal beta, PetscReal gamma) 742 { 743 RotCtx *rc; 744 PetscInt cdim; 745 746 PetscFunctionBegin; 747 PetscCall(DMGetCoordinateDim(dm, &cdim)); 748 PetscCall(PetscMalloc1(1, &rc)); 749 dm->transformCtx = rc; 750 dm->transformSetUp = DMPlexBasisTransformSetUp_Rotation_Internal; 751 dm->transformDestroy = DMPlexBasisTransformDestroy_Rotation_Internal; 752 dm->transformGetMatrix = DMPlexBasisTransformGetMatrix_Rotation_Internal; 753 rc->dim = cdim; 754 rc->alpha = alpha; 755 rc->beta = beta; 756 rc->gamma = gamma; 757 PetscCall((*dm->transformSetUp)(dm, dm->transformCtx)); 758 PetscCall(DMConstructBasisTransform_Internal(dm)); 759 PetscFunctionReturn(PETSC_SUCCESS); 760 } 761 762 /*@C 763 DMPlexInsertBoundaryValuesEssential - Insert boundary values into a local vector using a function of the coordinates 764 765 Input Parameters: 766 + dm - The `DM`, with a `PetscDS` that matches the problem being constrained 767 . time - The time 768 . field - The field to constrain 769 . Nc - The number of constrained field components, or 0 for all components 770 . comps - An array of constrained component numbers, or NULL for all components 771 . label - The `DMLabel` defining constrained points 772 . numids - The number of `DMLabel` ids for constrained points 773 . ids - An array of ids for constrained points 774 . func - A pointwise function giving boundary values 775 - ctx - An optional user context for bcFunc 776 777 Output Parameter: 778 . locX - A local vector to receives the boundary values 779 780 Level: developer 781 782 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMLabel`, `DMPlexInsertBoundaryValuesEssentialField()`, `DMPlexInsertBoundaryValuesEssentialBdField()`, `DMAddBoundary()` 783 @*/ 784 PetscErrorCode DMPlexInsertBoundaryValuesEssential(DM dm, PetscReal time, PetscInt field, PetscInt Nc, const PetscInt comps[], DMLabel label, PetscInt numids, const PetscInt ids[], PetscErrorCode (*func)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void *ctx, Vec locX) 785 { 786 PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx); 787 void **ctxs; 788 PetscInt numFields; 789 790 PetscFunctionBegin; 791 PetscCall(DMGetNumFields(dm, &numFields)); 792 PetscCall(PetscCalloc2(numFields, &funcs, numFields, &ctxs)); 793 funcs[field] = func; 794 ctxs[field] = ctx; 795 PetscCall(DMProjectFunctionLabelLocal(dm, time, label, numids, ids, Nc, comps, funcs, ctxs, INSERT_BC_VALUES, locX)); 796 PetscCall(PetscFree2(funcs, ctxs)); 797 PetscFunctionReturn(PETSC_SUCCESS); 798 } 799 800 /*@C 801 DMPlexInsertBoundaryValuesEssentialField - Insert boundary values into a local vector using a function of the coordinates and field data 802 803 Input Parameters: 804 + dm - The `DM`, with a `PetscDS` that matches the problem being constrained 805 . time - The time 806 . locU - A local vector with the input solution values 807 . field - The field to constrain 808 . Nc - The number of constrained field components, or 0 for all components 809 . comps - An array of constrained component numbers, or NULL for all components 810 . label - The `DMLabel` defining constrained points 811 . numids - The number of `DMLabel` ids for constrained points 812 . ids - An array of ids for constrained points 813 . func - A pointwise function giving boundary values 814 - ctx - An optional user context for bcFunc 815 816 Output Parameter: 817 . locX - A local vector to receives the boundary values 818 819 Level: developer 820 821 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexInsertBoundaryValuesEssential()`, `DMPlexInsertBoundaryValuesEssentialBdField()`, `DMAddBoundary()` 822 @*/ 823 PetscErrorCode DMPlexInsertBoundaryValuesEssentialField(DM dm, PetscReal time, Vec locU, PetscInt field, PetscInt Nc, const PetscInt comps[], DMLabel label, PetscInt numids, const PetscInt ids[], void (*func)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), void *ctx, Vec locX) 824 { 825 void (**funcs)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]); 826 void **ctxs; 827 PetscInt numFields; 828 829 PetscFunctionBegin; 830 PetscCall(DMGetNumFields(dm, &numFields)); 831 PetscCall(PetscCalloc2(numFields, &funcs, numFields, &ctxs)); 832 funcs[field] = func; 833 ctxs[field] = ctx; 834 PetscCall(DMProjectFieldLabelLocal(dm, time, label, numids, ids, Nc, comps, locU, funcs, INSERT_BC_VALUES, locX)); 835 PetscCall(PetscFree2(funcs, ctxs)); 836 PetscFunctionReturn(PETSC_SUCCESS); 837 } 838 839 /*@C 840 DMPlexInsertBoundaryValuesEssentialBdField - Insert boundary values into a local vector using a function of the coordinates and boundary field data 841 842 Collective on dm 843 844 Input Parameters: 845 + dm - The `DM`, with a `PetscDS` that matches the problem being constrained 846 . time - The time 847 . locU - A local vector with the input solution values 848 . field - The field to constrain 849 . Nc - The number of constrained field components, or 0 for all components 850 . comps - An array of constrained component numbers, or NULL for all components 851 . label - The `DMLabel` defining constrained points 852 . numids - The number of `DMLabel` ids for constrained points 853 . ids - An array of ids for constrained points 854 . func - A pointwise function giving boundary values, the calling sequence is given in DMProjectBdFieldLabelLocal() 855 - ctx - An optional user context for bcFunc 856 857 Output Parameter: 858 . locX - A local vector to receive the boundary values 859 860 Level: developer 861 862 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMProjectBdFieldLabelLocal()`, `DMPlexInsertBoundaryValuesEssential()`, `DMPlexInsertBoundaryValuesEssentialField()`, `DMAddBoundary()` 863 @*/ 864 PetscErrorCode DMPlexInsertBoundaryValuesEssentialBdField(DM dm, PetscReal time, Vec locU, PetscInt field, PetscInt Nc, const PetscInt comps[], DMLabel label, PetscInt numids, const PetscInt ids[], void (*func)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), void *ctx, Vec locX) 865 { 866 void (**funcs)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]); 867 void **ctxs; 868 PetscInt numFields; 869 870 PetscFunctionBegin; 871 PetscCall(DMGetNumFields(dm, &numFields)); 872 PetscCall(PetscCalloc2(numFields, &funcs, numFields, &ctxs)); 873 funcs[field] = func; 874 ctxs[field] = ctx; 875 PetscCall(DMProjectBdFieldLabelLocal(dm, time, label, numids, ids, Nc, comps, locU, funcs, INSERT_BC_VALUES, locX)); 876 PetscCall(PetscFree2(funcs, ctxs)); 877 PetscFunctionReturn(PETSC_SUCCESS); 878 } 879 880 /*@C 881 DMPlexInsertBoundaryValuesRiemann - Insert boundary values into a local vector 882 883 Input Parameters: 884 + dm - The `DM`, with a `PetscDS` that matches the problem being constrained 885 . time - The time 886 . faceGeometry - A vector with the FVM face geometry information 887 . cellGeometry - A vector with the FVM cell geometry information 888 . Grad - A vector with the FVM cell gradient information 889 . field - The field to constrain 890 . Nc - The number of constrained field components, or 0 for all components 891 . comps - An array of constrained component numbers, or NULL for all components 892 . label - The `DMLabel` defining constrained points 893 . numids - The number of `DMLabel` ids for constrained points 894 . ids - An array of ids for constrained points 895 . func - A pointwise function giving boundary values 896 - ctx - An optional user context for bcFunc 897 898 Output Parameter: 899 . locX - A local vector to receives the boundary values 900 901 Level: developer 902 903 Note: 904 This implementation currently ignores the numcomps/comps argument from `DMAddBoundary()` 905 906 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexInsertBoundaryValuesEssential()`, `DMPlexInsertBoundaryValuesEssentialField()`, `DMAddBoundary()` 907 @*/ 908 PetscErrorCode DMPlexInsertBoundaryValuesRiemann(DM dm, PetscReal time, Vec faceGeometry, Vec cellGeometry, Vec Grad, PetscInt field, PetscInt Nc, const PetscInt comps[], DMLabel label, PetscInt numids, const PetscInt ids[], PetscErrorCode (*func)(PetscReal, const PetscReal *, const PetscReal *, const PetscScalar *, PetscScalar *, void *), void *ctx, Vec locX) 909 { 910 PetscDS prob; 911 PetscSF sf; 912 DM dmFace, dmCell, dmGrad; 913 const PetscScalar *facegeom, *cellgeom = NULL, *grad; 914 const PetscInt *leaves; 915 PetscScalar *x, *fx; 916 PetscInt dim, nleaves, loc, fStart, fEnd, pdim, i; 917 PetscErrorCode ierru = PETSC_SUCCESS; 918 919 PetscFunctionBegin; 920 PetscCall(DMGetPointSF(dm, &sf)); 921 PetscCall(PetscSFGetGraph(sf, NULL, &nleaves, &leaves, NULL)); 922 nleaves = PetscMax(0, nleaves); 923 PetscCall(DMGetDimension(dm, &dim)); 924 PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 925 PetscCall(DMGetDS(dm, &prob)); 926 PetscCall(VecGetDM(faceGeometry, &dmFace)); 927 PetscCall(VecGetArrayRead(faceGeometry, &facegeom)); 928 if (cellGeometry) { 929 PetscCall(VecGetDM(cellGeometry, &dmCell)); 930 PetscCall(VecGetArrayRead(cellGeometry, &cellgeom)); 931 } 932 if (Grad) { 933 PetscFV fv; 934 935 PetscCall(PetscDSGetDiscretization(prob, field, (PetscObject *)&fv)); 936 PetscCall(VecGetDM(Grad, &dmGrad)); 937 PetscCall(VecGetArrayRead(Grad, &grad)); 938 PetscCall(PetscFVGetNumComponents(fv, &pdim)); 939 PetscCall(DMGetWorkArray(dm, pdim, MPIU_SCALAR, &fx)); 940 } 941 PetscCall(VecGetArray(locX, &x)); 942 for (i = 0; i < numids; ++i) { 943 IS faceIS; 944 const PetscInt *faces; 945 PetscInt numFaces, f; 946 947 PetscCall(DMLabelGetStratumIS(label, ids[i], &faceIS)); 948 if (!faceIS) continue; /* No points with that id on this process */ 949 PetscCall(ISGetLocalSize(faceIS, &numFaces)); 950 PetscCall(ISGetIndices(faceIS, &faces)); 951 for (f = 0; f < numFaces; ++f) { 952 const PetscInt face = faces[f], *cells; 953 PetscFVFaceGeom *fg; 954 955 if ((face < fStart) || (face >= fEnd)) continue; /* Refinement adds non-faces to labels */ 956 PetscCall(PetscFindInt(face, nleaves, (PetscInt *)leaves, &loc)); 957 if (loc >= 0) continue; 958 PetscCall(DMPlexPointLocalRead(dmFace, face, facegeom, &fg)); 959 PetscCall(DMPlexGetSupport(dm, face, &cells)); 960 if (Grad) { 961 PetscFVCellGeom *cg; 962 PetscScalar *cx, *cgrad; 963 PetscScalar *xG; 964 PetscReal dx[3]; 965 PetscInt d; 966 967 PetscCall(DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cg)); 968 PetscCall(DMPlexPointLocalRead(dm, cells[0], x, &cx)); 969 PetscCall(DMPlexPointLocalRead(dmGrad, cells[0], grad, &cgrad)); 970 PetscCall(DMPlexPointLocalFieldRef(dm, cells[1], field, x, &xG)); 971 DMPlex_WaxpyD_Internal(dim, -1, cg->centroid, fg->centroid, dx); 972 for (d = 0; d < pdim; ++d) fx[d] = cx[d] + DMPlex_DotD_Internal(dim, &cgrad[d * dim], dx); 973 PetscCall((*func)(time, fg->centroid, fg->normal, fx, xG, ctx)); 974 } else { 975 PetscScalar *xI; 976 PetscScalar *xG; 977 978 PetscCall(DMPlexPointLocalRead(dm, cells[0], x, &xI)); 979 PetscCall(DMPlexPointLocalFieldRef(dm, cells[1], field, x, &xG)); 980 ierru = (*func)(time, fg->centroid, fg->normal, xI, xG, ctx); 981 if (ierru) { 982 PetscCall(ISRestoreIndices(faceIS, &faces)); 983 PetscCall(ISDestroy(&faceIS)); 984 goto cleanup; 985 } 986 } 987 } 988 PetscCall(ISRestoreIndices(faceIS, &faces)); 989 PetscCall(ISDestroy(&faceIS)); 990 } 991 cleanup: 992 PetscCall(VecRestoreArray(locX, &x)); 993 if (Grad) { 994 PetscCall(DMRestoreWorkArray(dm, pdim, MPIU_SCALAR, &fx)); 995 PetscCall(VecRestoreArrayRead(Grad, &grad)); 996 } 997 if (cellGeometry) PetscCall(VecRestoreArrayRead(cellGeometry, &cellgeom)); 998 PetscCall(VecRestoreArrayRead(faceGeometry, &facegeom)); 999 PetscCall(ierru); 1000 PetscFunctionReturn(PETSC_SUCCESS); 1001 } 1002 1003 static PetscErrorCode zero(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx) 1004 { 1005 PetscInt c; 1006 for (c = 0; c < Nc; ++c) u[c] = 0.0; 1007 return PETSC_SUCCESS; 1008 } 1009 1010 PetscErrorCode DMPlexInsertBoundaryValues_Plex(DM dm, PetscBool insertEssential, Vec locX, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM) 1011 { 1012 PetscObject isZero; 1013 PetscDS prob; 1014 PetscInt numBd, b; 1015 1016 PetscFunctionBegin; 1017 PetscCall(DMGetDS(dm, &prob)); 1018 PetscCall(PetscDSGetNumBoundary(prob, &numBd)); 1019 PetscCall(PetscObjectQuery((PetscObject)locX, "__Vec_bc_zero__", &isZero)); 1020 for (b = 0; b < numBd; ++b) { 1021 PetscWeakForm wf; 1022 DMBoundaryConditionType type; 1023 const char *name; 1024 DMLabel label; 1025 PetscInt field, Nc; 1026 const PetscInt *comps; 1027 PetscObject obj; 1028 PetscClassId id; 1029 void (*bvfunc)(void); 1030 PetscInt numids; 1031 const PetscInt *ids; 1032 void *ctx; 1033 1034 PetscCall(PetscDSGetBoundary(prob, b, &wf, &type, &name, &label, &numids, &ids, &field, &Nc, &comps, &bvfunc, NULL, &ctx)); 1035 if (insertEssential != (type & DM_BC_ESSENTIAL)) continue; 1036 PetscCall(DMGetField(dm, field, NULL, &obj)); 1037 PetscCall(PetscObjectGetClassId(obj, &id)); 1038 if (id == PETSCFE_CLASSID) { 1039 switch (type) { 1040 /* for FEM, there is no insertion to be done for non-essential boundary conditions */ 1041 case DM_BC_ESSENTIAL: { 1042 PetscSimplePointFunc func = (PetscSimplePointFunc)bvfunc; 1043 1044 if (isZero) func = zero; 1045 PetscCall(DMPlexLabelAddCells(dm, label)); 1046 PetscCall(DMPlexInsertBoundaryValuesEssential(dm, time, field, Nc, comps, label, numids, ids, func, ctx, locX)); 1047 PetscCall(DMPlexLabelClearCells(dm, label)); 1048 } break; 1049 case DM_BC_ESSENTIAL_FIELD: { 1050 PetscPointFunc func = (PetscPointFunc)bvfunc; 1051 1052 PetscCall(DMPlexLabelAddCells(dm, label)); 1053 PetscCall(DMPlexInsertBoundaryValuesEssentialField(dm, time, locX, field, Nc, comps, label, numids, ids, func, ctx, locX)); 1054 PetscCall(DMPlexLabelClearCells(dm, label)); 1055 } break; 1056 default: 1057 break; 1058 } 1059 } else if (id == PETSCFV_CLASSID) { 1060 { 1061 PetscErrorCode (*func)(PetscReal, const PetscReal *, const PetscReal *, const PetscScalar *, PetscScalar *, void *) = (PetscErrorCode(*)(PetscReal, const PetscReal *, const PetscReal *, const PetscScalar *, PetscScalar *, void *))bvfunc; 1062 1063 if (!faceGeomFVM) continue; 1064 PetscCall(DMPlexInsertBoundaryValuesRiemann(dm, time, faceGeomFVM, cellGeomFVM, gradFVM, field, Nc, comps, label, numids, ids, func, ctx, locX)); 1065 } 1066 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 1067 } 1068 PetscFunctionReturn(PETSC_SUCCESS); 1069 } 1070 1071 PetscErrorCode DMPlexInsertTimeDerivativeBoundaryValues_Plex(DM dm, PetscBool insertEssential, Vec locX, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM) 1072 { 1073 PetscObject isZero; 1074 PetscDS prob; 1075 PetscInt numBd, b; 1076 1077 PetscFunctionBegin; 1078 if (!locX) PetscFunctionReturn(PETSC_SUCCESS); 1079 PetscCall(DMGetDS(dm, &prob)); 1080 PetscCall(PetscDSGetNumBoundary(prob, &numBd)); 1081 PetscCall(PetscObjectQuery((PetscObject)locX, "__Vec_bc_zero__", &isZero)); 1082 for (b = 0; b < numBd; ++b) { 1083 PetscWeakForm wf; 1084 DMBoundaryConditionType type; 1085 const char *name; 1086 DMLabel label; 1087 PetscInt field, Nc; 1088 const PetscInt *comps; 1089 PetscObject obj; 1090 PetscClassId id; 1091 PetscInt numids; 1092 const PetscInt *ids; 1093 void (*bvfunc)(void); 1094 void *ctx; 1095 1096 PetscCall(PetscDSGetBoundary(prob, b, &wf, &type, &name, &label, &numids, &ids, &field, &Nc, &comps, NULL, &bvfunc, &ctx)); 1097 if (insertEssential != (type & DM_BC_ESSENTIAL)) continue; 1098 PetscCall(DMGetField(dm, field, NULL, &obj)); 1099 PetscCall(PetscObjectGetClassId(obj, &id)); 1100 if (id == PETSCFE_CLASSID) { 1101 switch (type) { 1102 /* for FEM, there is no insertion to be done for non-essential boundary conditions */ 1103 case DM_BC_ESSENTIAL: { 1104 PetscSimplePointFunc func_t = (PetscSimplePointFunc)bvfunc; 1105 1106 if (isZero) func_t = zero; 1107 PetscCall(DMPlexLabelAddCells(dm, label)); 1108 PetscCall(DMPlexInsertBoundaryValuesEssential(dm, time, field, Nc, comps, label, numids, ids, func_t, ctx, locX)); 1109 PetscCall(DMPlexLabelClearCells(dm, label)); 1110 } break; 1111 case DM_BC_ESSENTIAL_FIELD: { 1112 PetscPointFunc func_t = (PetscPointFunc)bvfunc; 1113 1114 PetscCall(DMPlexLabelAddCells(dm, label)); 1115 PetscCall(DMPlexInsertBoundaryValuesEssentialField(dm, time, locX, field, Nc, comps, label, numids, ids, func_t, ctx, locX)); 1116 PetscCall(DMPlexLabelClearCells(dm, label)); 1117 } break; 1118 default: 1119 break; 1120 } 1121 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 1122 } 1123 PetscFunctionReturn(PETSC_SUCCESS); 1124 } 1125 1126 /*@ 1127 DMPlexInsertBoundaryValues - Puts coefficients which represent boundary values into the local solution vector 1128 1129 Not Collective 1130 1131 Input Parameters: 1132 + dm - The `DM` 1133 . insertEssential - Should I insert essential (e.g. Dirichlet) or inessential (e.g. Neumann) boundary conditions 1134 . time - The time 1135 . faceGeomFVM - Face geometry data for FV discretizations 1136 . cellGeomFVM - Cell geometry data for FV discretizations 1137 - gradFVM - Gradient reconstruction data for FV discretizations 1138 1139 Output Parameters: 1140 . locX - Solution updated with boundary values 1141 1142 Level: intermediate 1143 1144 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMProjectFunctionLabelLocal()`, `DMAddBoundary()` 1145 @*/ 1146 PetscErrorCode DMPlexInsertBoundaryValues(DM dm, PetscBool insertEssential, Vec locX, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM) 1147 { 1148 PetscFunctionBegin; 1149 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1150 PetscValidHeaderSpecific(locX, VEC_CLASSID, 3); 1151 if (faceGeomFVM) PetscValidHeaderSpecific(faceGeomFVM, VEC_CLASSID, 5); 1152 if (cellGeomFVM) PetscValidHeaderSpecific(cellGeomFVM, VEC_CLASSID, 6); 1153 if (gradFVM) PetscValidHeaderSpecific(gradFVM, VEC_CLASSID, 7); 1154 PetscTryMethod(dm, "DMPlexInsertBoundaryValues_C", (DM, PetscBool, Vec, PetscReal, Vec, Vec, Vec), (dm, insertEssential, locX, time, faceGeomFVM, cellGeomFVM, gradFVM)); 1155 PetscFunctionReturn(PETSC_SUCCESS); 1156 } 1157 1158 /*@ 1159 DMPlexInsertTimeDerivativeBoundaryValues - Puts coefficients which represent boundary values of the time derivative into the local solution vector 1160 1161 Input Parameters: 1162 + dm - The `DM` 1163 . insertEssential - Should I insert essential (e.g. Dirichlet) or inessential (e.g. Neumann) boundary conditions 1164 . time - The time 1165 . faceGeomFVM - Face geometry data for FV discretizations 1166 . cellGeomFVM - Cell geometry data for FV discretizations 1167 - gradFVM - Gradient reconstruction data for FV discretizations 1168 1169 Output Parameters: 1170 . locX_t - Solution updated with boundary values 1171 1172 Level: developer 1173 1174 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMProjectFunctionLabelLocal()` 1175 @*/ 1176 PetscErrorCode DMPlexInsertTimeDerivativeBoundaryValues(DM dm, PetscBool insertEssential, Vec locX_t, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM) 1177 { 1178 PetscFunctionBegin; 1179 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1180 if (locX_t) PetscValidHeaderSpecific(locX_t, VEC_CLASSID, 3); 1181 if (faceGeomFVM) PetscValidHeaderSpecific(faceGeomFVM, VEC_CLASSID, 5); 1182 if (cellGeomFVM) PetscValidHeaderSpecific(cellGeomFVM, VEC_CLASSID, 6); 1183 if (gradFVM) PetscValidHeaderSpecific(gradFVM, VEC_CLASSID, 7); 1184 PetscTryMethod(dm, "DMPlexInsertTimeDerviativeBoundaryValues_C", (DM, PetscBool, Vec, PetscReal, Vec, Vec, Vec), (dm, insertEssential, locX_t, time, faceGeomFVM, cellGeomFVM, gradFVM)); 1185 PetscFunctionReturn(PETSC_SUCCESS); 1186 } 1187 1188 PetscErrorCode DMComputeL2Diff_Plex(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff) 1189 { 1190 Vec localX; 1191 1192 PetscFunctionBegin; 1193 PetscCall(DMGetLocalVector(dm, &localX)); 1194 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, localX, time, NULL, NULL, NULL)); 1195 PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX)); 1196 PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX)); 1197 PetscCall(DMPlexComputeL2DiffLocal(dm, time, funcs, ctxs, localX, diff)); 1198 PetscCall(DMRestoreLocalVector(dm, &localX)); 1199 PetscFunctionReturn(PETSC_SUCCESS); 1200 } 1201 1202 /*@C 1203 DMComputeL2DiffLocal - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h. 1204 1205 Collective on dm 1206 1207 Input Parameters: 1208 + dm - The `DM` 1209 . time - The time 1210 . funcs - The functions to evaluate for each field component 1211 . ctxs - Optional array of contexts to pass to each function, or NULL. 1212 - localX - The coefficient vector u_h, a local vector 1213 1214 Output Parameter: 1215 . diff - The diff ||u - u_h||_2 1216 1217 Level: developer 1218 1219 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMProjectFunction()`, `DMComputeL2FieldDiff()`, `DMComputeL2GradientDiff()` 1220 @*/ 1221 PetscErrorCode DMPlexComputeL2DiffLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec localX, PetscReal *diff) 1222 { 1223 const PetscInt debug = ((DM_Plex *)dm->data)->printL2; 1224 DM tdm; 1225 Vec tv; 1226 PetscSection section; 1227 PetscQuadrature quad; 1228 PetscFEGeom fegeom; 1229 PetscScalar *funcVal, *interpolant; 1230 PetscReal *coords, *gcoords; 1231 PetscReal localDiff = 0.0; 1232 const PetscReal *quadWeights; 1233 PetscInt dim, coordDim, numFields, numComponents = 0, qNc, Nq, cellHeight, cStart, cEnd, c, field, fieldOffset; 1234 PetscBool transform; 1235 1236 PetscFunctionBegin; 1237 PetscCall(DMGetDimension(dm, &dim)); 1238 PetscCall(DMGetCoordinateDim(dm, &coordDim)); 1239 fegeom.dimEmbed = coordDim; 1240 PetscCall(DMGetLocalSection(dm, §ion)); 1241 PetscCall(PetscSectionGetNumFields(section, &numFields)); 1242 PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm)); 1243 PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 1244 PetscCall(DMHasBasisTransform(dm, &transform)); 1245 for (field = 0; field < numFields; ++field) { 1246 PetscObject obj; 1247 PetscClassId id; 1248 PetscInt Nc; 1249 1250 PetscCall(DMGetField(dm, field, NULL, &obj)); 1251 PetscCall(PetscObjectGetClassId(obj, &id)); 1252 if (id == PETSCFE_CLASSID) { 1253 PetscFE fe = (PetscFE)obj; 1254 1255 PetscCall(PetscFEGetQuadrature(fe, &quad)); 1256 PetscCall(PetscFEGetNumComponents(fe, &Nc)); 1257 } else if (id == PETSCFV_CLASSID) { 1258 PetscFV fv = (PetscFV)obj; 1259 1260 PetscCall(PetscFVGetQuadrature(fv, &quad)); 1261 PetscCall(PetscFVGetNumComponents(fv, &Nc)); 1262 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 1263 numComponents += Nc; 1264 } 1265 PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, NULL, &quadWeights)); 1266 PetscCheck(!(qNc != 1) || !(qNc != numComponents), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, numComponents); 1267 PetscCall(PetscMalloc6(numComponents, &funcVal, numComponents, &interpolant, coordDim * (Nq + 1), &coords, Nq, &fegeom.detJ, coordDim * coordDim * Nq, &fegeom.J, coordDim * coordDim * Nq, &fegeom.invJ)); 1268 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1269 PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 1270 for (c = cStart; c < cEnd; ++c) { 1271 PetscScalar *x = NULL; 1272 PetscReal elemDiff = 0.0; 1273 PetscInt qc = 0; 1274 1275 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 1276 PetscCall(DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x)); 1277 1278 for (field = 0, fieldOffset = 0; field < numFields; ++field) { 1279 PetscObject obj; 1280 PetscClassId id; 1281 void *const ctx = ctxs ? ctxs[field] : NULL; 1282 PetscInt Nb, Nc, q, fc; 1283 1284 PetscCall(DMGetField(dm, field, NULL, &obj)); 1285 PetscCall(PetscObjectGetClassId(obj, &id)); 1286 if (id == PETSCFE_CLASSID) { 1287 PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc)); 1288 PetscCall(PetscFEGetDimension((PetscFE)obj, &Nb)); 1289 } else if (id == PETSCFV_CLASSID) { 1290 PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc)); 1291 Nb = 1; 1292 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 1293 if (debug) { 1294 char title[1024]; 1295 PetscCall(PetscSNPrintf(title, 1023, "Solution for Field %" PetscInt_FMT, field)); 1296 PetscCall(DMPrintCellVector(c, title, Nb, &x[fieldOffset])); 1297 } 1298 for (q = 0; q < Nq; ++q) { 1299 PetscFEGeom qgeom; 1300 PetscErrorCode ierr; 1301 1302 qgeom.dimEmbed = fegeom.dimEmbed; 1303 qgeom.J = &fegeom.J[q * coordDim * coordDim]; 1304 qgeom.invJ = &fegeom.invJ[q * coordDim * coordDim]; 1305 qgeom.detJ = &fegeom.detJ[q]; 1306 PetscCheck(fegeom.detJ[q] > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %" PetscInt_FMT ", point %" PetscInt_FMT, (double)fegeom.detJ[q], c, q); 1307 if (transform) { 1308 gcoords = &coords[coordDim * Nq]; 1309 PetscCall(DMPlexBasisTransformApplyReal_Internal(dm, &coords[coordDim * q], PETSC_TRUE, coordDim, &coords[coordDim * q], gcoords, dm->transformCtx)); 1310 } else { 1311 gcoords = &coords[coordDim * q]; 1312 } 1313 PetscCall(PetscArrayzero(funcVal, Nc)); 1314 ierr = (*funcs[field])(coordDim, time, gcoords, Nc, funcVal, ctx); 1315 if (ierr) { 1316 PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x)); 1317 PetscCall(DMRestoreLocalVector(dm, &localX)); 1318 PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 1319 } 1320 if (transform) PetscCall(DMPlexBasisTransformApply_Internal(dm, &coords[coordDim * q], PETSC_FALSE, Nc, funcVal, funcVal, dm->transformCtx)); 1321 if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolate_Static((PetscFE)obj, &x[fieldOffset], &qgeom, q, interpolant)); 1322 else if (id == PETSCFV_CLASSID) PetscCall(PetscFVInterpolate_Static((PetscFV)obj, &x[fieldOffset], q, interpolant)); 1323 else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 1324 for (fc = 0; fc < Nc; ++fc) { 1325 const PetscReal wt = quadWeights[q * qNc + (qNc == 1 ? 0 : qc + fc)]; 1326 if (debug) 1327 PetscCall(PetscPrintf(PETSC_COMM_SELF, " elem %" PetscInt_FMT " field %" PetscInt_FMT ",%" PetscInt_FMT " point %g %g %g diff %g (%g, %g)\n", c, field, fc, (double)(coordDim > 0 ? coords[coordDim * q] : 0.), (double)(coordDim > 1 ? coords[coordDim * q + 1] : 0.), (double)(coordDim > 2 ? coords[coordDim * q + 2] : 0.), 1328 (double)(PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q]), (double)PetscRealPart(interpolant[fc]), (double)PetscRealPart(funcVal[fc]))); 1329 elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q]; 1330 } 1331 } 1332 fieldOffset += Nb; 1333 qc += Nc; 1334 } 1335 PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x)); 1336 if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, " elem %" PetscInt_FMT " diff %g\n", c, (double)elemDiff)); 1337 localDiff += elemDiff; 1338 } 1339 PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 1340 PetscCall(MPIU_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm))); 1341 *diff = PetscSqrtReal(*diff); 1342 PetscFunctionReturn(PETSC_SUCCESS); 1343 } 1344 1345 PetscErrorCode DMComputeL2GradientDiff_Plex(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, const PetscReal n[], PetscReal *diff) 1346 { 1347 const PetscInt debug = ((DM_Plex *)dm->data)->printL2; 1348 DM tdm; 1349 PetscSection section; 1350 PetscQuadrature quad; 1351 Vec localX, tv; 1352 PetscScalar *funcVal, *interpolant; 1353 const PetscReal *quadWeights; 1354 PetscFEGeom fegeom; 1355 PetscReal *coords, *gcoords; 1356 PetscReal localDiff = 0.0; 1357 PetscInt dim, coordDim, qNc = 0, Nq = 0, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset; 1358 PetscBool transform; 1359 1360 PetscFunctionBegin; 1361 PetscCall(DMGetDimension(dm, &dim)); 1362 PetscCall(DMGetCoordinateDim(dm, &coordDim)); 1363 fegeom.dimEmbed = coordDim; 1364 PetscCall(DMGetLocalSection(dm, §ion)); 1365 PetscCall(PetscSectionGetNumFields(section, &numFields)); 1366 PetscCall(DMGetLocalVector(dm, &localX)); 1367 PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX)); 1368 PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX)); 1369 PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm)); 1370 PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 1371 PetscCall(DMHasBasisTransform(dm, &transform)); 1372 for (field = 0; field < numFields; ++field) { 1373 PetscFE fe; 1374 PetscInt Nc; 1375 1376 PetscCall(DMGetField(dm, field, NULL, (PetscObject *)&fe)); 1377 PetscCall(PetscFEGetQuadrature(fe, &quad)); 1378 PetscCall(PetscFEGetNumComponents(fe, &Nc)); 1379 numComponents += Nc; 1380 } 1381 PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, NULL, &quadWeights)); 1382 PetscCheck(!(qNc != 1) || !(qNc != numComponents), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, numComponents); 1383 /* PetscCall(DMProjectFunctionLocal(dm, fe, funcs, INSERT_BC_VALUES, localX)); */ 1384 PetscCall(PetscMalloc6(numComponents, &funcVal, coordDim * (Nq + 1), &coords, coordDim * coordDim * Nq, &fegeom.J, coordDim * coordDim * Nq, &fegeom.invJ, numComponents * coordDim, &interpolant, Nq, &fegeom.detJ)); 1385 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 1386 for (c = cStart; c < cEnd; ++c) { 1387 PetscScalar *x = NULL; 1388 PetscReal elemDiff = 0.0; 1389 PetscInt qc = 0; 1390 1391 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 1392 PetscCall(DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x)); 1393 1394 for (field = 0, fieldOffset = 0; field < numFields; ++field) { 1395 PetscFE fe; 1396 void *const ctx = ctxs ? ctxs[field] : NULL; 1397 PetscInt Nb, Nc, q, fc; 1398 1399 PetscCall(DMGetField(dm, field, NULL, (PetscObject *)&fe)); 1400 PetscCall(PetscFEGetDimension(fe, &Nb)); 1401 PetscCall(PetscFEGetNumComponents(fe, &Nc)); 1402 if (debug) { 1403 char title[1024]; 1404 PetscCall(PetscSNPrintf(title, 1023, "Solution for Field %" PetscInt_FMT, field)); 1405 PetscCall(DMPrintCellVector(c, title, Nb, &x[fieldOffset])); 1406 } 1407 for (q = 0; q < Nq; ++q) { 1408 PetscFEGeom qgeom; 1409 PetscErrorCode ierr; 1410 1411 qgeom.dimEmbed = fegeom.dimEmbed; 1412 qgeom.J = &fegeom.J[q * coordDim * coordDim]; 1413 qgeom.invJ = &fegeom.invJ[q * coordDim * coordDim]; 1414 qgeom.detJ = &fegeom.detJ[q]; 1415 PetscCheck(fegeom.detJ[q] > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %" PetscInt_FMT ", quadrature points %" PetscInt_FMT, (double)fegeom.detJ[q], c, q); 1416 if (transform) { 1417 gcoords = &coords[coordDim * Nq]; 1418 PetscCall(DMPlexBasisTransformApplyReal_Internal(dm, &coords[coordDim * q], PETSC_TRUE, coordDim, &coords[coordDim * q], gcoords, dm->transformCtx)); 1419 } else { 1420 gcoords = &coords[coordDim * q]; 1421 } 1422 PetscCall(PetscArrayzero(funcVal, Nc)); 1423 ierr = (*funcs[field])(coordDim, time, gcoords, n, Nc, funcVal, ctx); 1424 if (ierr) { 1425 PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x)); 1426 PetscCall(DMRestoreLocalVector(dm, &localX)); 1427 PetscCall(PetscFree6(funcVal, coords, fegeom.J, fegeom.invJ, interpolant, fegeom.detJ)); 1428 } 1429 if (transform) PetscCall(DMPlexBasisTransformApply_Internal(dm, &coords[coordDim * q], PETSC_FALSE, Nc, funcVal, funcVal, dm->transformCtx)); 1430 PetscCall(PetscFEInterpolateGradient_Static(fe, 1, &x[fieldOffset], &qgeom, q, interpolant)); 1431 /* Overwrite with the dot product if the normal is given */ 1432 if (n) { 1433 for (fc = 0; fc < Nc; ++fc) { 1434 PetscScalar sum = 0.0; 1435 PetscInt d; 1436 for (d = 0; d < dim; ++d) sum += interpolant[fc * dim + d] * n[d]; 1437 interpolant[fc] = sum; 1438 } 1439 } 1440 for (fc = 0; fc < Nc; ++fc) { 1441 const PetscReal wt = quadWeights[q * qNc + (qNc == 1 ? 0 : qc + fc)]; 1442 if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, " elem %" PetscInt_FMT " fieldDer %" PetscInt_FMT ",%" PetscInt_FMT " diff %g\n", c, field, fc, (double)(PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q]))); 1443 elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q]; 1444 } 1445 } 1446 fieldOffset += Nb; 1447 qc += Nc; 1448 } 1449 PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x)); 1450 if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, " elem %" PetscInt_FMT " diff %g\n", c, (double)elemDiff)); 1451 localDiff += elemDiff; 1452 } 1453 PetscCall(PetscFree6(funcVal, coords, fegeom.J, fegeom.invJ, interpolant, fegeom.detJ)); 1454 PetscCall(DMRestoreLocalVector(dm, &localX)); 1455 PetscCall(MPIU_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm))); 1456 *diff = PetscSqrtReal(*diff); 1457 PetscFunctionReturn(PETSC_SUCCESS); 1458 } 1459 1460 PetscErrorCode DMComputeL2FieldDiff_Plex(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff) 1461 { 1462 const PetscInt debug = ((DM_Plex *)dm->data)->printL2; 1463 DM tdm; 1464 DMLabel depthLabel; 1465 PetscSection section; 1466 Vec localX, tv; 1467 PetscReal *localDiff; 1468 PetscInt dim, depth, dE, Nf, f, Nds, s; 1469 PetscBool transform; 1470 1471 PetscFunctionBegin; 1472 PetscCall(DMGetDimension(dm, &dim)); 1473 PetscCall(DMGetCoordinateDim(dm, &dE)); 1474 PetscCall(DMGetLocalSection(dm, §ion)); 1475 PetscCall(DMGetLocalVector(dm, &localX)); 1476 PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm)); 1477 PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 1478 PetscCall(DMHasBasisTransform(dm, &transform)); 1479 PetscCall(DMGetNumFields(dm, &Nf)); 1480 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 1481 PetscCall(DMLabelGetNumValues(depthLabel, &depth)); 1482 1483 PetscCall(VecSet(localX, 0.0)); 1484 PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX)); 1485 PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX)); 1486 PetscCall(DMProjectFunctionLocal(dm, time, funcs, ctxs, INSERT_BC_VALUES, localX)); 1487 PetscCall(DMGetNumDS(dm, &Nds)); 1488 PetscCall(PetscCalloc1(Nf, &localDiff)); 1489 for (s = 0; s < Nds; ++s) { 1490 PetscDS ds; 1491 DMLabel label; 1492 IS fieldIS, pointIS; 1493 const PetscInt *fields, *points = NULL; 1494 PetscQuadrature quad; 1495 const PetscReal *quadPoints, *quadWeights; 1496 PetscFEGeom fegeom; 1497 PetscReal *coords, *gcoords; 1498 PetscScalar *funcVal, *interpolant; 1499 PetscBool isCohesive; 1500 PetscInt qNc, Nq, totNc, cStart = 0, cEnd, c, dsNf; 1501 1502 PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds)); 1503 PetscCall(ISGetIndices(fieldIS, &fields)); 1504 PetscCall(PetscDSIsCohesive(ds, &isCohesive)); 1505 PetscCall(PetscDSGetNumFields(ds, &dsNf)); 1506 PetscCall(PetscDSGetTotalComponents(ds, &totNc)); 1507 PetscCall(PetscDSGetQuadrature(ds, &quad)); 1508 PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights)); 1509 PetscCheck(!(qNc != 1) || !(qNc != totNc), PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, totNc); 1510 PetscCall(PetscCalloc6(totNc, &funcVal, totNc, &interpolant, dE * (Nq + 1), &coords, Nq, &fegeom.detJ, dE * dE * Nq, &fegeom.J, dE * dE * Nq, &fegeom.invJ)); 1511 if (!label) { 1512 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 1513 } else { 1514 PetscCall(DMLabelGetStratumIS(label, 1, &pointIS)); 1515 PetscCall(ISGetLocalSize(pointIS, &cEnd)); 1516 PetscCall(ISGetIndices(pointIS, &points)); 1517 } 1518 for (c = cStart; c < cEnd; ++c) { 1519 const PetscInt cell = points ? points[c] : c; 1520 PetscScalar *x = NULL; 1521 const PetscInt *cone; 1522 PetscInt qc = 0, fOff = 0, dep; 1523 1524 PetscCall(DMLabelGetValue(depthLabel, cell, &dep)); 1525 if (dep != depth - 1) continue; 1526 if (isCohesive) { 1527 PetscCall(DMPlexGetCone(dm, cell, &cone)); 1528 PetscCall(DMPlexComputeCellGeometryFEM(dm, cone[0], quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 1529 } else { 1530 PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 1531 } 1532 PetscCall(DMPlexVecGetClosure(dm, NULL, localX, cell, NULL, &x)); 1533 for (f = 0; f < dsNf; ++f) { 1534 PetscObject obj; 1535 PetscClassId id; 1536 void *const ctx = ctxs ? ctxs[fields[f]] : NULL; 1537 PetscInt Nb, Nc, q, fc; 1538 PetscReal elemDiff = 0.0; 1539 PetscBool cohesive; 1540 1541 PetscCall(PetscDSGetCohesive(ds, f, &cohesive)); 1542 if (isCohesive && !cohesive) continue; 1543 PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 1544 PetscCall(PetscObjectGetClassId(obj, &id)); 1545 if (id == PETSCFE_CLASSID) { 1546 PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc)); 1547 PetscCall(PetscFEGetDimension((PetscFE)obj, &Nb)); 1548 } else if (id == PETSCFV_CLASSID) { 1549 PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc)); 1550 Nb = 1; 1551 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, fields[f]); 1552 if (debug) { 1553 char title[1024]; 1554 PetscCall(PetscSNPrintf(title, 1023, "Solution for Field %" PetscInt_FMT, fields[f])); 1555 PetscCall(DMPrintCellVector(cell, title, Nb, &x[fOff])); 1556 } 1557 for (q = 0; q < Nq; ++q) { 1558 PetscFEGeom qgeom; 1559 PetscErrorCode ierr; 1560 1561 qgeom.dimEmbed = fegeom.dimEmbed; 1562 qgeom.J = &fegeom.J[q * dE * dE]; 1563 qgeom.invJ = &fegeom.invJ[q * dE * dE]; 1564 qgeom.detJ = &fegeom.detJ[q]; 1565 PetscCheck(fegeom.detJ[q] > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for cell %" PetscInt_FMT ", quadrature point %" PetscInt_FMT, (double)fegeom.detJ[q], cell, q); 1566 if (transform) { 1567 gcoords = &coords[dE * Nq]; 1568 PetscCall(DMPlexBasisTransformApplyReal_Internal(dm, &coords[dE * q], PETSC_TRUE, dE, &coords[dE * q], gcoords, dm->transformCtx)); 1569 } else { 1570 gcoords = &coords[dE * q]; 1571 } 1572 for (fc = 0; fc < Nc; ++fc) funcVal[fc] = 0.; 1573 ierr = (*funcs[fields[f]])(dE, time, gcoords, Nc, funcVal, ctx); 1574 if (ierr) { 1575 PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, cell, NULL, &x)); 1576 PetscCall(DMRestoreLocalVector(dm, &localX)); 1577 PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 1578 } 1579 if (transform) PetscCall(DMPlexBasisTransformApply_Internal(dm, &coords[dE * q], PETSC_FALSE, Nc, funcVal, funcVal, dm->transformCtx)); 1580 /* Call once for each face, except for lagrange field */ 1581 if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolate_Static((PetscFE)obj, &x[fOff], &qgeom, q, interpolant)); 1582 else if (id == PETSCFV_CLASSID) PetscCall(PetscFVInterpolate_Static((PetscFV)obj, &x[fOff], q, interpolant)); 1583 else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, fields[f]); 1584 for (fc = 0; fc < Nc; ++fc) { 1585 const PetscReal wt = quadWeights[q * qNc + (qNc == 1 ? 0 : qc + fc)]; 1586 if (debug) 1587 PetscCall(PetscPrintf(PETSC_COMM_SELF, " cell %" PetscInt_FMT " field %" PetscInt_FMT ",%" PetscInt_FMT " point %g %g %g diff %g\n", cell, fields[f], fc, (double)(dE > 0 ? coords[dE * q] : 0.), (double)(dE > 1 ? coords[dE * q + 1] : 0.), (double)(dE > 2 ? coords[dE * q + 2] : 0.), 1588 (double)(PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q]))); 1589 elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q]; 1590 } 1591 } 1592 fOff += Nb; 1593 qc += Nc; 1594 localDiff[fields[f]] += elemDiff; 1595 if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, " cell %" PetscInt_FMT " field %" PetscInt_FMT " cum diff %g\n", cell, fields[f], (double)localDiff[fields[f]])); 1596 } 1597 PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, cell, NULL, &x)); 1598 } 1599 if (label) { 1600 PetscCall(ISRestoreIndices(pointIS, &points)); 1601 PetscCall(ISDestroy(&pointIS)); 1602 } 1603 PetscCall(ISRestoreIndices(fieldIS, &fields)); 1604 PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 1605 } 1606 PetscCall(DMRestoreLocalVector(dm, &localX)); 1607 PetscCall(MPIU_Allreduce(localDiff, diff, Nf, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm))); 1608 PetscCall(PetscFree(localDiff)); 1609 for (f = 0; f < Nf; ++f) diff[f] = PetscSqrtReal(diff[f]); 1610 PetscFunctionReturn(PETSC_SUCCESS); 1611 } 1612 1613 /*@C 1614 DMPlexComputeL2DiffVec - This function computes the cellwise L_2 difference between a function u and an FEM interpolant solution u_h, and stores it in a Vec. 1615 1616 Collective on dm 1617 1618 Input Parameters: 1619 + dm - The `DM` 1620 . time - The time 1621 . funcs - The functions to evaluate for each field component: NULL means that component does not contribute to error calculation 1622 . ctxs - Optional array of contexts to pass to each function, or NULL. 1623 - X - The coefficient vector u_h 1624 1625 Output Parameter: 1626 . D - A Vec which holds the difference ||u - u_h||_2 for each cell 1627 1628 Level: developer 1629 1630 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMPlexComputeL2FieldDiff()`, `DMComputeL2GradientDiff()` 1631 @*/ 1632 PetscErrorCode DMPlexComputeL2DiffVec(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, Vec D) 1633 { 1634 PetscSection section; 1635 PetscQuadrature quad; 1636 Vec localX; 1637 PetscFEGeom fegeom; 1638 PetscScalar *funcVal, *interpolant; 1639 PetscReal *coords; 1640 const PetscReal *quadPoints, *quadWeights; 1641 PetscInt dim, coordDim, numFields, numComponents = 0, qNc, Nq, cStart, cEnd, c, field, fieldOffset; 1642 1643 PetscFunctionBegin; 1644 PetscCall(VecSet(D, 0.0)); 1645 PetscCall(DMGetDimension(dm, &dim)); 1646 PetscCall(DMGetCoordinateDim(dm, &coordDim)); 1647 PetscCall(DMGetLocalSection(dm, §ion)); 1648 PetscCall(PetscSectionGetNumFields(section, &numFields)); 1649 PetscCall(DMGetLocalVector(dm, &localX)); 1650 PetscCall(DMProjectFunctionLocal(dm, time, funcs, ctxs, INSERT_BC_VALUES, localX)); 1651 PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX)); 1652 PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX)); 1653 for (field = 0; field < numFields; ++field) { 1654 PetscObject obj; 1655 PetscClassId id; 1656 PetscInt Nc; 1657 1658 PetscCall(DMGetField(dm, field, NULL, &obj)); 1659 PetscCall(PetscObjectGetClassId(obj, &id)); 1660 if (id == PETSCFE_CLASSID) { 1661 PetscFE fe = (PetscFE)obj; 1662 1663 PetscCall(PetscFEGetQuadrature(fe, &quad)); 1664 PetscCall(PetscFEGetNumComponents(fe, &Nc)); 1665 } else if (id == PETSCFV_CLASSID) { 1666 PetscFV fv = (PetscFV)obj; 1667 1668 PetscCall(PetscFVGetQuadrature(fv, &quad)); 1669 PetscCall(PetscFVGetNumComponents(fv, &Nc)); 1670 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 1671 numComponents += Nc; 1672 } 1673 PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights)); 1674 PetscCheck(!(qNc != 1) || !(qNc != numComponents), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, numComponents); 1675 PetscCall(PetscMalloc6(numComponents, &funcVal, numComponents, &interpolant, coordDim * Nq, &coords, Nq, &fegeom.detJ, coordDim * coordDim * Nq, &fegeom.J, coordDim * coordDim * Nq, &fegeom.invJ)); 1676 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 1677 for (c = cStart; c < cEnd; ++c) { 1678 PetscScalar *x = NULL; 1679 PetscScalar elemDiff = 0.0; 1680 PetscInt qc = 0; 1681 1682 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 1683 PetscCall(DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x)); 1684 1685 for (field = 0, fieldOffset = 0; field < numFields; ++field) { 1686 PetscObject obj; 1687 PetscClassId id; 1688 void *const ctx = ctxs ? ctxs[field] : NULL; 1689 PetscInt Nb, Nc, q, fc; 1690 1691 PetscCall(DMGetField(dm, field, NULL, &obj)); 1692 PetscCall(PetscObjectGetClassId(obj, &id)); 1693 if (id == PETSCFE_CLASSID) { 1694 PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc)); 1695 PetscCall(PetscFEGetDimension((PetscFE)obj, &Nb)); 1696 } else if (id == PETSCFV_CLASSID) { 1697 PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc)); 1698 Nb = 1; 1699 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 1700 if (funcs[field]) { 1701 for (q = 0; q < Nq; ++q) { 1702 PetscFEGeom qgeom; 1703 1704 qgeom.dimEmbed = fegeom.dimEmbed; 1705 qgeom.J = &fegeom.J[q * coordDim * coordDim]; 1706 qgeom.invJ = &fegeom.invJ[q * coordDim * coordDim]; 1707 qgeom.detJ = &fegeom.detJ[q]; 1708 PetscCheck(fegeom.detJ[q] > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %" PetscInt_FMT ", quadrature points %" PetscInt_FMT, (double)fegeom.detJ[q], c, q); 1709 PetscCall((*funcs[field])(coordDim, time, &coords[q * coordDim], Nc, funcVal, ctx)); 1710 #if defined(needs_fix_with_return_code_argument) 1711 if (ierr) { 1712 PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x)); 1713 PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 1714 PetscCall(DMRestoreLocalVector(dm, &localX)); 1715 } 1716 #endif 1717 if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolate_Static((PetscFE)obj, &x[fieldOffset], &qgeom, q, interpolant)); 1718 else if (id == PETSCFV_CLASSID) PetscCall(PetscFVInterpolate_Static((PetscFV)obj, &x[fieldOffset], q, interpolant)); 1719 else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 1720 for (fc = 0; fc < Nc; ++fc) { 1721 const PetscReal wt = quadWeights[q * qNc + (qNc == 1 ? 0 : qc + fc)]; 1722 elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc])) * wt * fegeom.detJ[q]; 1723 } 1724 } 1725 } 1726 fieldOffset += Nb; 1727 qc += Nc; 1728 } 1729 PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x)); 1730 PetscCall(VecSetValue(D, c - cStart, elemDiff, INSERT_VALUES)); 1731 } 1732 PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 1733 PetscCall(DMRestoreLocalVector(dm, &localX)); 1734 PetscCall(VecSqrtAbs(D)); 1735 PetscFunctionReturn(PETSC_SUCCESS); 1736 } 1737 1738 /*@ 1739 DMPlexComputeClementInterpolant - This function computes the L2 projection of the cellwise values of a function u onto P1, and stores it in a Vec. 1740 1741 Collective on dm 1742 1743 Input Parameters: 1744 + dm - The `DM` 1745 - locX - The coefficient vector u_h 1746 1747 Output Parameter: 1748 . locC - A `Vec` which holds the Clement interpolant of the function 1749 1750 Level: developer 1751 1752 Note: 1753 $ u_h(v_i) = \sum_{T_i \in support(v_i)} |T_i| u_h(T_i) / \sum_{T_i \in support(v_i)} |T_i| $ where $ |T_i| $ is the cell volume 1754 1755 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMPlexComputeL2FieldDiff()`, `DMComputeL2GradientDiff()` 1756 @*/ 1757 PetscErrorCode DMPlexComputeClementInterpolant(DM dm, Vec locX, Vec locC) 1758 { 1759 PetscInt debug = ((DM_Plex *)dm->data)->printFEM; 1760 DM dmc; 1761 PetscQuadrature quad; 1762 PetscScalar *interpolant, *valsum; 1763 PetscFEGeom fegeom; 1764 PetscReal *coords; 1765 const PetscReal *quadPoints, *quadWeights; 1766 PetscInt dim, cdim, Nf, f, Nc = 0, Nq, qNc, cStart, cEnd, vStart, vEnd, v; 1767 1768 PetscFunctionBegin; 1769 PetscCall(PetscCitationsRegister(ClementCitation, &Clementcite)); 1770 PetscCall(VecGetDM(locC, &dmc)); 1771 PetscCall(VecSet(locC, 0.0)); 1772 PetscCall(DMGetDimension(dm, &dim)); 1773 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1774 fegeom.dimEmbed = cdim; 1775 PetscCall(DMGetNumFields(dm, &Nf)); 1776 PetscCheck(Nf > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fields is zero!"); 1777 for (f = 0; f < Nf; ++f) { 1778 PetscObject obj; 1779 PetscClassId id; 1780 PetscInt fNc; 1781 1782 PetscCall(DMGetField(dm, f, NULL, &obj)); 1783 PetscCall(PetscObjectGetClassId(obj, &id)); 1784 if (id == PETSCFE_CLASSID) { 1785 PetscFE fe = (PetscFE)obj; 1786 1787 PetscCall(PetscFEGetQuadrature(fe, &quad)); 1788 PetscCall(PetscFEGetNumComponents(fe, &fNc)); 1789 } else if (id == PETSCFV_CLASSID) { 1790 PetscFV fv = (PetscFV)obj; 1791 1792 PetscCall(PetscFVGetQuadrature(fv, &quad)); 1793 PetscCall(PetscFVGetNumComponents(fv, &fNc)); 1794 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f); 1795 Nc += fNc; 1796 } 1797 PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights)); 1798 PetscCheck(qNc == 1, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " > 1", qNc); 1799 PetscCall(PetscMalloc6(Nc * 2, &valsum, Nc, &interpolant, cdim * Nq, &coords, Nq, &fegeom.detJ, cdim * cdim * Nq, &fegeom.J, cdim * cdim * Nq, &fegeom.invJ)); 1800 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1801 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 1802 for (v = vStart; v < vEnd; ++v) { 1803 PetscScalar volsum = 0.0; 1804 PetscInt *star = NULL; 1805 PetscInt starSize, st, fc; 1806 1807 PetscCall(PetscArrayzero(valsum, Nc)); 1808 PetscCall(DMPlexGetTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star)); 1809 for (st = 0; st < starSize * 2; st += 2) { 1810 const PetscInt cell = star[st]; 1811 PetscScalar *val = &valsum[Nc]; 1812 PetscScalar *x = NULL; 1813 PetscReal vol = 0.0; 1814 PetscInt foff = 0; 1815 1816 if ((cell < cStart) || (cell >= cEnd)) continue; 1817 PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 1818 PetscCall(DMPlexVecGetClosure(dm, NULL, locX, cell, NULL, &x)); 1819 for (f = 0; f < Nf; ++f) { 1820 PetscObject obj; 1821 PetscClassId id; 1822 PetscInt Nb, fNc, q; 1823 1824 PetscCall(PetscArrayzero(val, Nc)); 1825 PetscCall(DMGetField(dm, f, NULL, &obj)); 1826 PetscCall(PetscObjectGetClassId(obj, &id)); 1827 if (id == PETSCFE_CLASSID) { 1828 PetscCall(PetscFEGetNumComponents((PetscFE)obj, &fNc)); 1829 PetscCall(PetscFEGetDimension((PetscFE)obj, &Nb)); 1830 } else if (id == PETSCFV_CLASSID) { 1831 PetscCall(PetscFVGetNumComponents((PetscFV)obj, &fNc)); 1832 Nb = 1; 1833 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f); 1834 for (q = 0; q < Nq; ++q) { 1835 const PetscReal wt = quadWeights[q] * fegeom.detJ[q]; 1836 PetscFEGeom qgeom; 1837 1838 qgeom.dimEmbed = fegeom.dimEmbed; 1839 qgeom.J = &fegeom.J[q * cdim * cdim]; 1840 qgeom.invJ = &fegeom.invJ[q * cdim * cdim]; 1841 qgeom.detJ = &fegeom.detJ[q]; 1842 PetscCheck(fegeom.detJ[q] > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %" PetscInt_FMT ", quadrature points %" PetscInt_FMT, (double)fegeom.detJ[q], cell, q); 1843 if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolate_Static((PetscFE)obj, &x[foff], &qgeom, q, interpolant)); 1844 else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f); 1845 for (fc = 0; fc < fNc; ++fc) val[foff + fc] += interpolant[fc] * wt; 1846 vol += wt; 1847 } 1848 foff += Nb; 1849 } 1850 PetscCall(DMPlexVecRestoreClosure(dm, NULL, locX, cell, NULL, &x)); 1851 for (fc = 0; fc < Nc; ++fc) valsum[fc] += val[fc]; 1852 volsum += vol; 1853 if (debug) { 1854 PetscCall(PetscPrintf(PETSC_COMM_SELF, "Vertex %" PetscInt_FMT " Cell %" PetscInt_FMT " value: [", v, cell)); 1855 for (fc = 0; fc < Nc; ++fc) { 1856 if (fc) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", ")); 1857 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g", (double)PetscRealPart(val[fc]))); 1858 } 1859 PetscCall(PetscPrintf(PETSC_COMM_SELF, "]\n")); 1860 } 1861 } 1862 for (fc = 0; fc < Nc; ++fc) valsum[fc] /= volsum; 1863 PetscCall(DMPlexRestoreTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star)); 1864 PetscCall(DMPlexVecSetClosure(dmc, NULL, locC, v, valsum, INSERT_VALUES)); 1865 } 1866 PetscCall(PetscFree6(valsum, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 1867 PetscFunctionReturn(PETSC_SUCCESS); 1868 } 1869 1870 /*@ 1871 DMPlexComputeGradientClementInterpolant - This function computes the L2 projection of the cellwise gradient of a function u onto P1, and stores it in a Vec. 1872 1873 Collective on dm 1874 1875 Input Parameters: 1876 + dm - The `DM` 1877 - locX - The coefficient vector u_h 1878 1879 Output Parameter: 1880 . locC - A `Vec` which holds the Clement interpolant of the gradient 1881 1882 Level: developer 1883 1884 Note: 1885 $\nabla u_h(v_i) = \sum_{T_i \in support(v_i)} |T_i| \nabla u_h(T_i) / \sum_{T_i \in support(v_i)} |T_i| $ where $ |T_i| $ is the cell volume 1886 1887 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMPlexComputeL2FieldDiff()`, `DMComputeL2GradientDiff()` 1888 @*/ 1889 PetscErrorCode DMPlexComputeGradientClementInterpolant(DM dm, Vec locX, Vec locC) 1890 { 1891 DM_Plex *mesh = (DM_Plex *)dm->data; 1892 PetscInt debug = mesh->printFEM; 1893 DM dmC; 1894 PetscQuadrature quad; 1895 PetscScalar *interpolant, *gradsum; 1896 PetscFEGeom fegeom; 1897 PetscReal *coords; 1898 const PetscReal *quadPoints, *quadWeights; 1899 PetscInt dim, coordDim, numFields, numComponents = 0, qNc, Nq, cStart, cEnd, vStart, vEnd, v, field, fieldOffset; 1900 1901 PetscFunctionBegin; 1902 PetscCall(PetscCitationsRegister(ClementCitation, &Clementcite)); 1903 PetscCall(VecGetDM(locC, &dmC)); 1904 PetscCall(VecSet(locC, 0.0)); 1905 PetscCall(DMGetDimension(dm, &dim)); 1906 PetscCall(DMGetCoordinateDim(dm, &coordDim)); 1907 fegeom.dimEmbed = coordDim; 1908 PetscCall(DMGetNumFields(dm, &numFields)); 1909 PetscCheck(numFields, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fields is zero!"); 1910 for (field = 0; field < numFields; ++field) { 1911 PetscObject obj; 1912 PetscClassId id; 1913 PetscInt Nc; 1914 1915 PetscCall(DMGetField(dm, field, NULL, &obj)); 1916 PetscCall(PetscObjectGetClassId(obj, &id)); 1917 if (id == PETSCFE_CLASSID) { 1918 PetscFE fe = (PetscFE)obj; 1919 1920 PetscCall(PetscFEGetQuadrature(fe, &quad)); 1921 PetscCall(PetscFEGetNumComponents(fe, &Nc)); 1922 } else if (id == PETSCFV_CLASSID) { 1923 PetscFV fv = (PetscFV)obj; 1924 1925 PetscCall(PetscFVGetQuadrature(fv, &quad)); 1926 PetscCall(PetscFVGetNumComponents(fv, &Nc)); 1927 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 1928 numComponents += Nc; 1929 } 1930 PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights)); 1931 PetscCheck(!(qNc != 1) || !(qNc != numComponents), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Quadrature components %" PetscInt_FMT " != %" PetscInt_FMT " field components", qNc, numComponents); 1932 PetscCall(PetscMalloc6(coordDim * numComponents * 2, &gradsum, coordDim * numComponents, &interpolant, coordDim * Nq, &coords, Nq, &fegeom.detJ, coordDim * coordDim * Nq, &fegeom.J, coordDim * coordDim * Nq, &fegeom.invJ)); 1933 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1934 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 1935 for (v = vStart; v < vEnd; ++v) { 1936 PetscScalar volsum = 0.0; 1937 PetscInt *star = NULL; 1938 PetscInt starSize, st, d, fc; 1939 1940 PetscCall(PetscArrayzero(gradsum, coordDim * numComponents)); 1941 PetscCall(DMPlexGetTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star)); 1942 for (st = 0; st < starSize * 2; st += 2) { 1943 const PetscInt cell = star[st]; 1944 PetscScalar *grad = &gradsum[coordDim * numComponents]; 1945 PetscScalar *x = NULL; 1946 PetscReal vol = 0.0; 1947 1948 if ((cell < cStart) || (cell >= cEnd)) continue; 1949 PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 1950 PetscCall(DMPlexVecGetClosure(dm, NULL, locX, cell, NULL, &x)); 1951 for (field = 0, fieldOffset = 0; field < numFields; ++field) { 1952 PetscObject obj; 1953 PetscClassId id; 1954 PetscInt Nb, Nc, q, qc = 0; 1955 1956 PetscCall(PetscArrayzero(grad, coordDim * numComponents)); 1957 PetscCall(DMGetField(dm, field, NULL, &obj)); 1958 PetscCall(PetscObjectGetClassId(obj, &id)); 1959 if (id == PETSCFE_CLASSID) { 1960 PetscCall(PetscFEGetNumComponents((PetscFE)obj, &Nc)); 1961 PetscCall(PetscFEGetDimension((PetscFE)obj, &Nb)); 1962 } else if (id == PETSCFV_CLASSID) { 1963 PetscCall(PetscFVGetNumComponents((PetscFV)obj, &Nc)); 1964 Nb = 1; 1965 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 1966 for (q = 0; q < Nq; ++q) { 1967 PetscFEGeom qgeom; 1968 1969 qgeom.dimEmbed = fegeom.dimEmbed; 1970 qgeom.J = &fegeom.J[q * coordDim * coordDim]; 1971 qgeom.invJ = &fegeom.invJ[q * coordDim * coordDim]; 1972 qgeom.detJ = &fegeom.detJ[q]; 1973 PetscCheck(fegeom.detJ[q] > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %" PetscInt_FMT ", quadrature points %" PetscInt_FMT, (double)fegeom.detJ[q], cell, q); 1974 if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolateGradient_Static((PetscFE)obj, 1, &x[fieldOffset], &qgeom, q, interpolant)); 1975 else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 1976 for (fc = 0; fc < Nc; ++fc) { 1977 const PetscReal wt = quadWeights[q * qNc + qc]; 1978 1979 for (d = 0; d < coordDim; ++d) grad[fc * coordDim + d] += interpolant[fc * dim + d] * wt * fegeom.detJ[q]; 1980 } 1981 vol += quadWeights[q * qNc] * fegeom.detJ[q]; 1982 } 1983 fieldOffset += Nb; 1984 qc += Nc; 1985 } 1986 PetscCall(DMPlexVecRestoreClosure(dm, NULL, locX, cell, NULL, &x)); 1987 for (fc = 0; fc < numComponents; ++fc) { 1988 for (d = 0; d < coordDim; ++d) gradsum[fc * coordDim + d] += grad[fc * coordDim + d]; 1989 } 1990 volsum += vol; 1991 if (debug) { 1992 PetscCall(PetscPrintf(PETSC_COMM_SELF, "Vertex %" PetscInt_FMT " Cell %" PetscInt_FMT " gradient: [", v, cell)); 1993 for (fc = 0; fc < numComponents; ++fc) { 1994 for (d = 0; d < coordDim; ++d) { 1995 if (fc || d > 0) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", ")); 1996 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g", (double)PetscRealPart(grad[fc * coordDim + d]))); 1997 } 1998 } 1999 PetscCall(PetscPrintf(PETSC_COMM_SELF, "]\n")); 2000 } 2001 } 2002 for (fc = 0; fc < numComponents; ++fc) { 2003 for (d = 0; d < coordDim; ++d) gradsum[fc * coordDim + d] /= volsum; 2004 } 2005 PetscCall(DMPlexRestoreTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star)); 2006 PetscCall(DMPlexVecSetClosure(dmC, NULL, locC, v, gradsum, INSERT_VALUES)); 2007 } 2008 PetscCall(PetscFree6(gradsum, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 2009 PetscFunctionReturn(PETSC_SUCCESS); 2010 } 2011 2012 static PetscErrorCode DMPlexComputeIntegral_Internal(DM dm, Vec X, PetscInt cStart, PetscInt cEnd, PetscScalar *cintegral, void *user) 2013 { 2014 DM dmAux = NULL; 2015 PetscDS prob, probAux = NULL; 2016 PetscSection section, sectionAux; 2017 Vec locX, locA; 2018 PetscInt dim, numCells = cEnd - cStart, c, f; 2019 PetscBool useFVM = PETSC_FALSE; 2020 /* DS */ 2021 PetscInt Nf, totDim, *uOff, *uOff_x, numConstants; 2022 PetscInt NfAux, totDimAux, *aOff; 2023 PetscScalar *u, *a; 2024 const PetscScalar *constants; 2025 /* Geometry */ 2026 PetscFEGeom *cgeomFEM; 2027 DM dmGrad; 2028 PetscQuadrature affineQuad = NULL; 2029 Vec cellGeometryFVM = NULL, faceGeometryFVM = NULL, locGrad = NULL; 2030 PetscFVCellGeom *cgeomFVM; 2031 const PetscScalar *lgrad; 2032 PetscInt maxDegree; 2033 DMField coordField; 2034 IS cellIS; 2035 2036 PetscFunctionBegin; 2037 PetscCall(DMGetDS(dm, &prob)); 2038 PetscCall(DMGetDimension(dm, &dim)); 2039 PetscCall(DMGetLocalSection(dm, §ion)); 2040 PetscCall(DMGetNumFields(dm, &Nf)); 2041 /* Determine which discretizations we have */ 2042 for (f = 0; f < Nf; ++f) { 2043 PetscObject obj; 2044 PetscClassId id; 2045 2046 PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 2047 PetscCall(PetscObjectGetClassId(obj, &id)); 2048 if (id == PETSCFV_CLASSID) useFVM = PETSC_TRUE; 2049 } 2050 /* Get local solution with boundary values */ 2051 PetscCall(DMGetLocalVector(dm, &locX)); 2052 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locX, 0.0, NULL, NULL, NULL)); 2053 PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, locX)); 2054 PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, locX)); 2055 /* Read DS information */ 2056 PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 2057 PetscCall(PetscDSGetComponentOffsets(prob, &uOff)); 2058 PetscCall(PetscDSGetComponentDerivativeOffsets(prob, &uOff_x)); 2059 PetscCall(ISCreateStride(PETSC_COMM_SELF, numCells, cStart, 1, &cellIS)); 2060 PetscCall(PetscDSGetConstants(prob, &numConstants, &constants)); 2061 /* Read Auxiliary DS information */ 2062 PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &locA)); 2063 if (locA) { 2064 PetscCall(VecGetDM(locA, &dmAux)); 2065 PetscCall(DMGetDS(dmAux, &probAux)); 2066 PetscCall(PetscDSGetNumFields(probAux, &NfAux)); 2067 PetscCall(DMGetLocalSection(dmAux, §ionAux)); 2068 PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 2069 PetscCall(PetscDSGetComponentOffsets(probAux, &aOff)); 2070 } 2071 /* Allocate data arrays */ 2072 PetscCall(PetscCalloc1(numCells * totDim, &u)); 2073 if (dmAux) PetscCall(PetscMalloc1(numCells * totDimAux, &a)); 2074 /* Read out geometry */ 2075 PetscCall(DMGetCoordinateField(dm, &coordField)); 2076 PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 2077 if (maxDegree <= 1) { 2078 PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &affineQuad)); 2079 if (affineQuad) PetscCall(DMFieldCreateFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &cgeomFEM)); 2080 } 2081 if (useFVM) { 2082 PetscFV fv = NULL; 2083 Vec grad; 2084 PetscInt fStart, fEnd; 2085 PetscBool compGrad; 2086 2087 for (f = 0; f < Nf; ++f) { 2088 PetscObject obj; 2089 PetscClassId id; 2090 2091 PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 2092 PetscCall(PetscObjectGetClassId(obj, &id)); 2093 if (id == PETSCFV_CLASSID) { 2094 fv = (PetscFV)obj; 2095 break; 2096 } 2097 } 2098 PetscCall(PetscFVGetComputeGradients(fv, &compGrad)); 2099 PetscCall(PetscFVSetComputeGradients(fv, PETSC_TRUE)); 2100 PetscCall(DMPlexComputeGeometryFVM(dm, &cellGeometryFVM, &faceGeometryFVM)); 2101 PetscCall(DMPlexComputeGradientFVM(dm, fv, faceGeometryFVM, cellGeometryFVM, &dmGrad)); 2102 PetscCall(PetscFVSetComputeGradients(fv, compGrad)); 2103 PetscCall(VecGetArrayRead(cellGeometryFVM, (const PetscScalar **)&cgeomFVM)); 2104 /* Reconstruct and limit cell gradients */ 2105 PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 2106 PetscCall(DMGetGlobalVector(dmGrad, &grad)); 2107 PetscCall(DMPlexReconstructGradients_Internal(dm, fv, fStart, fEnd, faceGeometryFVM, cellGeometryFVM, locX, grad)); 2108 /* Communicate gradient values */ 2109 PetscCall(DMGetLocalVector(dmGrad, &locGrad)); 2110 PetscCall(DMGlobalToLocalBegin(dmGrad, grad, INSERT_VALUES, locGrad)); 2111 PetscCall(DMGlobalToLocalEnd(dmGrad, grad, INSERT_VALUES, locGrad)); 2112 PetscCall(DMRestoreGlobalVector(dmGrad, &grad)); 2113 /* Handle non-essential (e.g. outflow) boundary values */ 2114 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_FALSE, locX, 0.0, faceGeometryFVM, cellGeometryFVM, locGrad)); 2115 PetscCall(VecGetArrayRead(locGrad, &lgrad)); 2116 } 2117 /* Read out data from inputs */ 2118 for (c = cStart; c < cEnd; ++c) { 2119 PetscScalar *x = NULL; 2120 PetscInt i; 2121 2122 PetscCall(DMPlexVecGetClosure(dm, section, locX, c, NULL, &x)); 2123 for (i = 0; i < totDim; ++i) u[c * totDim + i] = x[i]; 2124 PetscCall(DMPlexVecRestoreClosure(dm, section, locX, c, NULL, &x)); 2125 if (dmAux) { 2126 PetscCall(DMPlexVecGetClosure(dmAux, sectionAux, locA, c, NULL, &x)); 2127 for (i = 0; i < totDimAux; ++i) a[c * totDimAux + i] = x[i]; 2128 PetscCall(DMPlexVecRestoreClosure(dmAux, sectionAux, locA, c, NULL, &x)); 2129 } 2130 } 2131 /* Do integration for each field */ 2132 for (f = 0; f < Nf; ++f) { 2133 PetscObject obj; 2134 PetscClassId id; 2135 PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset; 2136 2137 PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 2138 PetscCall(PetscObjectGetClassId(obj, &id)); 2139 if (id == PETSCFE_CLASSID) { 2140 PetscFE fe = (PetscFE)obj; 2141 PetscQuadrature q; 2142 PetscFEGeom *chunkGeom = NULL; 2143 PetscInt Nq, Nb; 2144 2145 PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 2146 PetscCall(PetscFEGetQuadrature(fe, &q)); 2147 PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Nq, NULL, NULL)); 2148 PetscCall(PetscFEGetDimension(fe, &Nb)); 2149 blockSize = Nb * Nq; 2150 batchSize = numBlocks * blockSize; 2151 PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 2152 numChunks = numCells / (numBatches * batchSize); 2153 Ne = numChunks * numBatches * batchSize; 2154 Nr = numCells % (numBatches * batchSize); 2155 offset = numCells - Nr; 2156 if (!affineQuad) PetscCall(DMFieldCreateFEGeom(coordField, cellIS, q, PETSC_FALSE, &cgeomFEM)); 2157 PetscCall(PetscFEGeomGetChunk(cgeomFEM, 0, offset, &chunkGeom)); 2158 PetscCall(PetscFEIntegrate(prob, f, Ne, chunkGeom, u, probAux, a, cintegral)); 2159 PetscCall(PetscFEGeomGetChunk(cgeomFEM, offset, numCells, &chunkGeom)); 2160 PetscCall(PetscFEIntegrate(prob, f, Nr, chunkGeom, &u[offset * totDim], probAux, &a[offset * totDimAux], &cintegral[offset * Nf])); 2161 PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, offset, numCells, &chunkGeom)); 2162 if (!affineQuad) PetscCall(PetscFEGeomDestroy(&cgeomFEM)); 2163 } else if (id == PETSCFV_CLASSID) { 2164 PetscInt foff; 2165 PetscPointFunc obj_func; 2166 PetscScalar lint; 2167 2168 PetscCall(PetscDSGetObjective(prob, f, &obj_func)); 2169 PetscCall(PetscDSGetFieldOffset(prob, f, &foff)); 2170 if (obj_func) { 2171 for (c = 0; c < numCells; ++c) { 2172 PetscScalar *u_x; 2173 2174 PetscCall(DMPlexPointLocalRead(dmGrad, c, lgrad, &u_x)); 2175 obj_func(dim, Nf, NfAux, uOff, uOff_x, &u[totDim * c + foff], NULL, u_x, aOff, NULL, &a[totDimAux * c], NULL, NULL, 0.0, cgeomFVM[c].centroid, numConstants, constants, &lint); 2176 cintegral[c * Nf + f] += PetscRealPart(lint) * cgeomFVM[c].volume; 2177 } 2178 } 2179 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f); 2180 } 2181 /* Cleanup data arrays */ 2182 if (useFVM) { 2183 PetscCall(VecRestoreArrayRead(locGrad, &lgrad)); 2184 PetscCall(VecRestoreArrayRead(cellGeometryFVM, (const PetscScalar **)&cgeomFVM)); 2185 PetscCall(DMRestoreLocalVector(dmGrad, &locGrad)); 2186 PetscCall(VecDestroy(&faceGeometryFVM)); 2187 PetscCall(VecDestroy(&cellGeometryFVM)); 2188 PetscCall(DMDestroy(&dmGrad)); 2189 } 2190 if (dmAux) PetscCall(PetscFree(a)); 2191 PetscCall(PetscFree(u)); 2192 /* Cleanup */ 2193 if (affineQuad) PetscCall(PetscFEGeomDestroy(&cgeomFEM)); 2194 PetscCall(PetscQuadratureDestroy(&affineQuad)); 2195 PetscCall(ISDestroy(&cellIS)); 2196 PetscCall(DMRestoreLocalVector(dm, &locX)); 2197 PetscFunctionReturn(PETSC_SUCCESS); 2198 } 2199 2200 /*@ 2201 DMPlexComputeIntegralFEM - Form the integral over the domain from the global input X using pointwise functions specified by the user 2202 2203 Input Parameters: 2204 + dm - The mesh 2205 . X - Global input vector 2206 - user - The user context 2207 2208 Output Parameter: 2209 . integral - Integral for each field 2210 2211 Level: developer 2212 2213 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexSNESComputeResidualFEM()` 2214 @*/ 2215 PetscErrorCode DMPlexComputeIntegralFEM(DM dm, Vec X, PetscScalar *integral, void *user) 2216 { 2217 DM_Plex *mesh = (DM_Plex *)dm->data; 2218 PetscScalar *cintegral, *lintegral; 2219 PetscInt Nf, f, cellHeight, cStart, cEnd, cell; 2220 2221 PetscFunctionBegin; 2222 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2223 PetscValidHeaderSpecific(X, VEC_CLASSID, 2); 2224 PetscValidScalarPointer(integral, 3); 2225 PetscCall(PetscLogEventBegin(DMPLEX_IntegralFEM, dm, 0, 0, 0)); 2226 PetscCall(DMGetNumFields(dm, &Nf)); 2227 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 2228 PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 2229 /* TODO Introduce a loop over large chunks (right now this is a single chunk) */ 2230 PetscCall(PetscCalloc2(Nf, &lintegral, (cEnd - cStart) * Nf, &cintegral)); 2231 PetscCall(DMPlexComputeIntegral_Internal(dm, X, cStart, cEnd, cintegral, user)); 2232 /* Sum up values */ 2233 for (cell = cStart; cell < cEnd; ++cell) { 2234 const PetscInt c = cell - cStart; 2235 2236 if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, "Cell Integral", Nf, &cintegral[c * Nf])); 2237 for (f = 0; f < Nf; ++f) lintegral[f] += cintegral[c * Nf + f]; 2238 } 2239 PetscCall(MPIU_Allreduce(lintegral, integral, Nf, MPIU_SCALAR, MPIU_SUM, PetscObjectComm((PetscObject)dm))); 2240 if (mesh->printFEM) { 2241 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "Integral:")); 2242 for (f = 0; f < Nf; ++f) PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), " %g", (double)PetscRealPart(integral[f]))); 2243 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "\n")); 2244 } 2245 PetscCall(PetscFree2(lintegral, cintegral)); 2246 PetscCall(PetscLogEventEnd(DMPLEX_IntegralFEM, dm, 0, 0, 0)); 2247 PetscFunctionReturn(PETSC_SUCCESS); 2248 } 2249 2250 /*@ 2251 DMPlexComputeCellwiseIntegralFEM - Form the vector of cellwise integrals F from the global input X using pointwise functions specified by the user 2252 2253 Input Parameters: 2254 + dm - The mesh 2255 . X - Global input vector 2256 - user - The user context 2257 2258 Output Parameter: 2259 . integral - Cellwise integrals for each field 2260 2261 Level: developer 2262 2263 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexSNESComputeResidualFEM()` 2264 @*/ 2265 PetscErrorCode DMPlexComputeCellwiseIntegralFEM(DM dm, Vec X, Vec F, void *user) 2266 { 2267 DM_Plex *mesh = (DM_Plex *)dm->data; 2268 DM dmF; 2269 PetscSection sectionF; 2270 PetscScalar *cintegral, *af; 2271 PetscInt Nf, f, cellHeight, cStart, cEnd, cell; 2272 2273 PetscFunctionBegin; 2274 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2275 PetscValidHeaderSpecific(X, VEC_CLASSID, 2); 2276 PetscValidHeaderSpecific(F, VEC_CLASSID, 3); 2277 PetscCall(PetscLogEventBegin(DMPLEX_IntegralFEM, dm, 0, 0, 0)); 2278 PetscCall(DMGetNumFields(dm, &Nf)); 2279 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 2280 PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 2281 /* TODO Introduce a loop over large chunks (right now this is a single chunk) */ 2282 PetscCall(PetscCalloc1((cEnd - cStart) * Nf, &cintegral)); 2283 PetscCall(DMPlexComputeIntegral_Internal(dm, X, cStart, cEnd, cintegral, user)); 2284 /* Put values in F*/ 2285 PetscCall(VecGetDM(F, &dmF)); 2286 PetscCall(DMGetLocalSection(dmF, §ionF)); 2287 PetscCall(VecGetArray(F, &af)); 2288 for (cell = cStart; cell < cEnd; ++cell) { 2289 const PetscInt c = cell - cStart; 2290 PetscInt dof, off; 2291 2292 if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, "Cell Integral", Nf, &cintegral[c * Nf])); 2293 PetscCall(PetscSectionGetDof(sectionF, cell, &dof)); 2294 PetscCall(PetscSectionGetOffset(sectionF, cell, &off)); 2295 PetscCheck(dof == Nf, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "The number of cell dofs %" PetscInt_FMT " != %" PetscInt_FMT, dof, Nf); 2296 for (f = 0; f < Nf; ++f) af[off + f] = cintegral[c * Nf + f]; 2297 } 2298 PetscCall(VecRestoreArray(F, &af)); 2299 PetscCall(PetscFree(cintegral)); 2300 PetscCall(PetscLogEventEnd(DMPLEX_IntegralFEM, dm, 0, 0, 0)); 2301 PetscFunctionReturn(PETSC_SUCCESS); 2302 } 2303 2304 static PetscErrorCode DMPlexComputeBdIntegral_Internal(DM dm, Vec locX, IS pointIS, void (*func)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), PetscScalar *fintegral, void *user) 2305 { 2306 DM plex = NULL, plexA = NULL; 2307 DMEnclosureType encAux; 2308 PetscDS prob, probAux = NULL; 2309 PetscSection section, sectionAux = NULL; 2310 Vec locA = NULL; 2311 DMField coordField; 2312 PetscInt Nf, totDim, *uOff, *uOff_x; 2313 PetscInt NfAux = 0, totDimAux = 0, *aOff = NULL; 2314 PetscScalar *u, *a = NULL; 2315 const PetscScalar *constants; 2316 PetscInt numConstants, f; 2317 2318 PetscFunctionBegin; 2319 PetscCall(DMGetCoordinateField(dm, &coordField)); 2320 PetscCall(DMConvert(dm, DMPLEX, &plex)); 2321 PetscCall(DMGetDS(dm, &prob)); 2322 PetscCall(DMGetLocalSection(dm, §ion)); 2323 PetscCall(PetscSectionGetNumFields(section, &Nf)); 2324 /* Determine which discretizations we have */ 2325 for (f = 0; f < Nf; ++f) { 2326 PetscObject obj; 2327 PetscClassId id; 2328 2329 PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 2330 PetscCall(PetscObjectGetClassId(obj, &id)); 2331 PetscCheck(id != PETSCFV_CLASSID, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Not supported for FVM (field %" PetscInt_FMT ")", f); 2332 } 2333 /* Read DS information */ 2334 PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 2335 PetscCall(PetscDSGetComponentOffsets(prob, &uOff)); 2336 PetscCall(PetscDSGetComponentDerivativeOffsets(prob, &uOff_x)); 2337 PetscCall(PetscDSGetConstants(prob, &numConstants, &constants)); 2338 /* Read Auxiliary DS information */ 2339 PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &locA)); 2340 if (locA) { 2341 DM dmAux; 2342 2343 PetscCall(VecGetDM(locA, &dmAux)); 2344 PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 2345 PetscCall(DMConvert(dmAux, DMPLEX, &plexA)); 2346 PetscCall(DMGetDS(dmAux, &probAux)); 2347 PetscCall(PetscDSGetNumFields(probAux, &NfAux)); 2348 PetscCall(DMGetLocalSection(dmAux, §ionAux)); 2349 PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 2350 PetscCall(PetscDSGetComponentOffsets(probAux, &aOff)); 2351 } 2352 /* Integrate over points */ 2353 { 2354 PetscFEGeom *fgeom, *chunkGeom = NULL; 2355 PetscInt maxDegree; 2356 PetscQuadrature qGeom = NULL; 2357 const PetscInt *points; 2358 PetscInt numFaces, face, Nq, field; 2359 PetscInt numChunks, chunkSize, chunk, Nr, offset; 2360 2361 PetscCall(ISGetLocalSize(pointIS, &numFaces)); 2362 PetscCall(ISGetIndices(pointIS, &points)); 2363 PetscCall(PetscCalloc2(numFaces * totDim, &u, locA ? numFaces * totDimAux : 0, &a)); 2364 PetscCall(DMFieldGetDegree(coordField, pointIS, NULL, &maxDegree)); 2365 for (field = 0; field < Nf; ++field) { 2366 PetscFE fe; 2367 2368 PetscCall(PetscDSGetDiscretization(prob, field, (PetscObject *)&fe)); 2369 if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, pointIS, &qGeom)); 2370 if (!qGeom) { 2371 PetscCall(PetscFEGetFaceQuadrature(fe, &qGeom)); 2372 PetscCall(PetscObjectReference((PetscObject)qGeom)); 2373 } 2374 PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL)); 2375 PetscCall(DMPlexGetFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 2376 for (face = 0; face < numFaces; ++face) { 2377 const PetscInt point = points[face], *support; 2378 PetscScalar *x = NULL; 2379 PetscInt i; 2380 2381 PetscCall(DMPlexGetSupport(dm, point, &support)); 2382 PetscCall(DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x)); 2383 for (i = 0; i < totDim; ++i) u[face * totDim + i] = x[i]; 2384 PetscCall(DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x)); 2385 if (locA) { 2386 PetscInt subp; 2387 PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp)); 2388 PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x)); 2389 for (i = 0; i < totDimAux; ++i) a[f * totDimAux + i] = x[i]; 2390 PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x)); 2391 } 2392 } 2393 /* Get blocking */ 2394 { 2395 PetscQuadrature q; 2396 PetscInt numBatches, batchSize, numBlocks, blockSize; 2397 PetscInt Nq, Nb; 2398 2399 PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 2400 PetscCall(PetscFEGetQuadrature(fe, &q)); 2401 PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Nq, NULL, NULL)); 2402 PetscCall(PetscFEGetDimension(fe, &Nb)); 2403 blockSize = Nb * Nq; 2404 batchSize = numBlocks * blockSize; 2405 chunkSize = numBatches * batchSize; 2406 PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 2407 numChunks = numFaces / chunkSize; 2408 Nr = numFaces % chunkSize; 2409 offset = numFaces - Nr; 2410 } 2411 /* Do integration for each field */ 2412 for (chunk = 0; chunk < numChunks; ++chunk) { 2413 PetscCall(PetscFEGeomGetChunk(fgeom, chunk * chunkSize, (chunk + 1) * chunkSize, &chunkGeom)); 2414 PetscCall(PetscFEIntegrateBd(prob, field, func, chunkSize, chunkGeom, u, probAux, a, fintegral)); 2415 PetscCall(PetscFEGeomRestoreChunk(fgeom, 0, offset, &chunkGeom)); 2416 } 2417 PetscCall(PetscFEGeomGetChunk(fgeom, offset, numFaces, &chunkGeom)); 2418 PetscCall(PetscFEIntegrateBd(prob, field, func, Nr, chunkGeom, &u[offset * totDim], probAux, a ? &a[offset * totDimAux] : NULL, &fintegral[offset * Nf])); 2419 PetscCall(PetscFEGeomRestoreChunk(fgeom, offset, numFaces, &chunkGeom)); 2420 /* Cleanup data arrays */ 2421 PetscCall(DMPlexRestoreFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 2422 PetscCall(PetscQuadratureDestroy(&qGeom)); 2423 PetscCall(PetscFree2(u, a)); 2424 PetscCall(ISRestoreIndices(pointIS, &points)); 2425 } 2426 } 2427 if (plex) PetscCall(DMDestroy(&plex)); 2428 if (plexA) PetscCall(DMDestroy(&plexA)); 2429 PetscFunctionReturn(PETSC_SUCCESS); 2430 } 2431 2432 /*@ 2433 DMPlexComputeBdIntegral - Form the integral over the specified boundary from the global input X using pointwise functions specified by the user 2434 2435 Input Parameters: 2436 + dm - The mesh 2437 . X - Global input vector 2438 . label - The boundary `DMLabel` 2439 . numVals - The number of label values to use, or `PETSC_DETERMINE` for all values 2440 . vals - The label values to use, or NULL for all values 2441 . func - The function to integrate along the boundary 2442 - user - The user context 2443 2444 Output Parameter: 2445 . integral - Integral for each field 2446 2447 Level: developer 2448 2449 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexComputeIntegralFEM()`, `DMPlexComputeBdResidualFEM()` 2450 @*/ 2451 PetscErrorCode DMPlexComputeBdIntegral(DM dm, Vec X, DMLabel label, PetscInt numVals, const PetscInt vals[], void (*func)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), PetscScalar *integral, void *user) 2452 { 2453 Vec locX; 2454 PetscSection section; 2455 DMLabel depthLabel; 2456 IS facetIS; 2457 PetscInt dim, Nf, f, v; 2458 2459 PetscFunctionBegin; 2460 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2461 PetscValidHeaderSpecific(X, VEC_CLASSID, 2); 2462 PetscValidPointer(label, 3); 2463 if (vals) PetscValidIntPointer(vals, 5); 2464 PetscValidScalarPointer(integral, 7); 2465 PetscCall(PetscLogEventBegin(DMPLEX_IntegralFEM, dm, 0, 0, 0)); 2466 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 2467 PetscCall(DMGetDimension(dm, &dim)); 2468 PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 2469 PetscCall(DMGetLocalSection(dm, §ion)); 2470 PetscCall(PetscSectionGetNumFields(section, &Nf)); 2471 /* Get local solution with boundary values */ 2472 PetscCall(DMGetLocalVector(dm, &locX)); 2473 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locX, 0.0, NULL, NULL, NULL)); 2474 PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, locX)); 2475 PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, locX)); 2476 /* Loop over label values */ 2477 PetscCall(PetscArrayzero(integral, Nf)); 2478 for (v = 0; v < numVals; ++v) { 2479 IS pointIS; 2480 PetscInt numFaces, face; 2481 PetscScalar *fintegral; 2482 2483 PetscCall(DMLabelGetStratumIS(label, vals[v], &pointIS)); 2484 if (!pointIS) continue; /* No points with that id on this process */ 2485 { 2486 IS isectIS; 2487 2488 /* TODO: Special cases of ISIntersect where it is quick to check a priori if one is a superset of the other */ 2489 PetscCall(ISIntersect_Caching_Internal(facetIS, pointIS, &isectIS)); 2490 PetscCall(ISDestroy(&pointIS)); 2491 pointIS = isectIS; 2492 } 2493 PetscCall(ISGetLocalSize(pointIS, &numFaces)); 2494 PetscCall(PetscCalloc1(numFaces * Nf, &fintegral)); 2495 PetscCall(DMPlexComputeBdIntegral_Internal(dm, locX, pointIS, func, fintegral, user)); 2496 /* Sum point contributions into integral */ 2497 for (f = 0; f < Nf; ++f) 2498 for (face = 0; face < numFaces; ++face) integral[f] += fintegral[face * Nf + f]; 2499 PetscCall(PetscFree(fintegral)); 2500 PetscCall(ISDestroy(&pointIS)); 2501 } 2502 PetscCall(DMRestoreLocalVector(dm, &locX)); 2503 PetscCall(ISDestroy(&facetIS)); 2504 PetscCall(PetscLogEventEnd(DMPLEX_IntegralFEM, dm, 0, 0, 0)); 2505 PetscFunctionReturn(PETSC_SUCCESS); 2506 } 2507 2508 /*@ 2509 DMPlexComputeInterpolatorNested - Form the local portion of the interpolation matrix I from the coarse `DM` to a uniformly refined `DM`. 2510 2511 Input Parameters: 2512 + dmc - The coarse mesh 2513 . dmf - The fine mesh 2514 . isRefined - Flag indicating regular refinement, rather than the same topology 2515 - user - The user context 2516 2517 Output Parameter: 2518 . In - The interpolation matrix 2519 2520 Level: developer 2521 2522 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexComputeInterpolatorGeneral()`, `DMPlexComputeJacobianFEM()` 2523 @*/ 2524 PetscErrorCode DMPlexComputeInterpolatorNested(DM dmc, DM dmf, PetscBool isRefined, Mat In, void *user) 2525 { 2526 DM_Plex *mesh = (DM_Plex *)dmc->data; 2527 const char *name = "Interpolator"; 2528 PetscFE *feRef; 2529 PetscFV *fvRef; 2530 PetscSection fsection, fglobalSection; 2531 PetscSection csection, cglobalSection; 2532 PetscScalar *elemMat; 2533 PetscInt dim, Nf, f, fieldI, fieldJ, offsetI, offsetJ, cStart, cEnd, c; 2534 PetscInt cTotDim = 0, rTotDim = 0; 2535 2536 PetscFunctionBegin; 2537 PetscCall(PetscLogEventBegin(DMPLEX_InterpolatorFEM, dmc, dmf, 0, 0)); 2538 PetscCall(DMGetDimension(dmf, &dim)); 2539 PetscCall(DMGetLocalSection(dmf, &fsection)); 2540 PetscCall(DMGetGlobalSection(dmf, &fglobalSection)); 2541 PetscCall(DMGetLocalSection(dmc, &csection)); 2542 PetscCall(DMGetGlobalSection(dmc, &cglobalSection)); 2543 PetscCall(PetscSectionGetNumFields(fsection, &Nf)); 2544 PetscCall(DMPlexGetSimplexOrBoxCells(dmc, 0, &cStart, &cEnd)); 2545 PetscCall(PetscCalloc2(Nf, &feRef, Nf, &fvRef)); 2546 for (f = 0; f < Nf; ++f) { 2547 PetscObject obj, objc; 2548 PetscClassId id, idc; 2549 PetscInt rNb = 0, Nc = 0, cNb = 0; 2550 2551 PetscCall(DMGetField(dmf, f, NULL, &obj)); 2552 PetscCall(PetscObjectGetClassId(obj, &id)); 2553 if (id == PETSCFE_CLASSID) { 2554 PetscFE fe = (PetscFE)obj; 2555 2556 if (isRefined) { 2557 PetscCall(PetscFERefine(fe, &feRef[f])); 2558 } else { 2559 PetscCall(PetscObjectReference((PetscObject)fe)); 2560 feRef[f] = fe; 2561 } 2562 PetscCall(PetscFEGetDimension(feRef[f], &rNb)); 2563 PetscCall(PetscFEGetNumComponents(fe, &Nc)); 2564 } else if (id == PETSCFV_CLASSID) { 2565 PetscFV fv = (PetscFV)obj; 2566 PetscDualSpace Q; 2567 2568 if (isRefined) { 2569 PetscCall(PetscFVRefine(fv, &fvRef[f])); 2570 } else { 2571 PetscCall(PetscObjectReference((PetscObject)fv)); 2572 fvRef[f] = fv; 2573 } 2574 PetscCall(PetscFVGetDualSpace(fvRef[f], &Q)); 2575 PetscCall(PetscDualSpaceGetDimension(Q, &rNb)); 2576 PetscCall(PetscFVGetDualSpace(fv, &Q)); 2577 PetscCall(PetscFVGetNumComponents(fv, &Nc)); 2578 } 2579 PetscCall(DMGetField(dmc, f, NULL, &objc)); 2580 PetscCall(PetscObjectGetClassId(objc, &idc)); 2581 if (idc == PETSCFE_CLASSID) { 2582 PetscFE fe = (PetscFE)objc; 2583 2584 PetscCall(PetscFEGetDimension(fe, &cNb)); 2585 } else if (id == PETSCFV_CLASSID) { 2586 PetscFV fv = (PetscFV)obj; 2587 PetscDualSpace Q; 2588 2589 PetscCall(PetscFVGetDualSpace(fv, &Q)); 2590 PetscCall(PetscDualSpaceGetDimension(Q, &cNb)); 2591 } 2592 rTotDim += rNb; 2593 cTotDim += cNb; 2594 } 2595 PetscCall(PetscMalloc1(rTotDim * cTotDim, &elemMat)); 2596 PetscCall(PetscArrayzero(elemMat, rTotDim * cTotDim)); 2597 for (fieldI = 0, offsetI = 0; fieldI < Nf; ++fieldI) { 2598 PetscDualSpace Qref; 2599 PetscQuadrature f; 2600 const PetscReal *qpoints, *qweights; 2601 PetscReal *points; 2602 PetscInt npoints = 0, Nc, Np, fpdim, i, k, p, d; 2603 2604 /* Compose points from all dual basis functionals */ 2605 if (feRef[fieldI]) { 2606 PetscCall(PetscFEGetDualSpace(feRef[fieldI], &Qref)); 2607 PetscCall(PetscFEGetNumComponents(feRef[fieldI], &Nc)); 2608 } else { 2609 PetscCall(PetscFVGetDualSpace(fvRef[fieldI], &Qref)); 2610 PetscCall(PetscFVGetNumComponents(fvRef[fieldI], &Nc)); 2611 } 2612 PetscCall(PetscDualSpaceGetDimension(Qref, &fpdim)); 2613 for (i = 0; i < fpdim; ++i) { 2614 PetscCall(PetscDualSpaceGetFunctional(Qref, i, &f)); 2615 PetscCall(PetscQuadratureGetData(f, NULL, NULL, &Np, NULL, NULL)); 2616 npoints += Np; 2617 } 2618 PetscCall(PetscMalloc1(npoints * dim, &points)); 2619 for (i = 0, k = 0; i < fpdim; ++i) { 2620 PetscCall(PetscDualSpaceGetFunctional(Qref, i, &f)); 2621 PetscCall(PetscQuadratureGetData(f, NULL, NULL, &Np, &qpoints, NULL)); 2622 for (p = 0; p < Np; ++p, ++k) 2623 for (d = 0; d < dim; ++d) points[k * dim + d] = qpoints[p * dim + d]; 2624 } 2625 2626 for (fieldJ = 0, offsetJ = 0; fieldJ < Nf; ++fieldJ) { 2627 PetscObject obj; 2628 PetscClassId id; 2629 PetscInt NcJ = 0, cpdim = 0, j, qNc; 2630 2631 PetscCall(DMGetField(dmc, fieldJ, NULL, &obj)); 2632 PetscCall(PetscObjectGetClassId(obj, &id)); 2633 if (id == PETSCFE_CLASSID) { 2634 PetscFE fe = (PetscFE)obj; 2635 PetscTabulation T = NULL; 2636 2637 /* Evaluate basis at points */ 2638 PetscCall(PetscFEGetNumComponents(fe, &NcJ)); 2639 PetscCall(PetscFEGetDimension(fe, &cpdim)); 2640 /* For now, fields only interpolate themselves */ 2641 if (fieldI == fieldJ) { 2642 PetscCheck(Nc == NcJ, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of components in fine space field %" PetscInt_FMT " does not match coarse field %" PetscInt_FMT, Nc, NcJ); 2643 PetscCall(PetscFECreateTabulation(fe, 1, npoints, points, 0, &T)); 2644 for (i = 0, k = 0; i < fpdim; ++i) { 2645 PetscCall(PetscDualSpaceGetFunctional(Qref, i, &f)); 2646 PetscCall(PetscQuadratureGetData(f, NULL, &qNc, &Np, NULL, &qweights)); 2647 PetscCheck(qNc == NcJ, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of components in quadrature %" PetscInt_FMT " does not match coarse field %" PetscInt_FMT, qNc, NcJ); 2648 for (p = 0; p < Np; ++p, ++k) { 2649 for (j = 0; j < cpdim; ++j) { 2650 /* 2651 cTotDim: Total columns in element interpolation matrix, sum of number of dual basis functionals in each field 2652 offsetI, offsetJ: Offsets into the larger element interpolation matrix for different fields 2653 fpdim, i, cpdim, j: Dofs for fine and coarse grids, correspond to dual space basis functionals 2654 qNC, Nc, Ncj, c: Number of components in this field 2655 Np, p: Number of quad points in the fine grid functional i 2656 k: i*Np + p, overall point number for the interpolation 2657 */ 2658 for (c = 0; c < Nc; ++c) elemMat[(offsetI + i) * cTotDim + offsetJ + j] += T->T[0][k * cpdim * NcJ + j * Nc + c] * qweights[p * qNc + c]; 2659 } 2660 } 2661 } 2662 PetscCall(PetscTabulationDestroy(&T)); 2663 } 2664 } else if (id == PETSCFV_CLASSID) { 2665 PetscFV fv = (PetscFV)obj; 2666 2667 /* Evaluate constant function at points */ 2668 PetscCall(PetscFVGetNumComponents(fv, &NcJ)); 2669 cpdim = 1; 2670 /* For now, fields only interpolate themselves */ 2671 if (fieldI == fieldJ) { 2672 PetscCheck(Nc == NcJ, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of components in fine space field %" PetscInt_FMT " does not match coarse field %" PetscInt_FMT, Nc, NcJ); 2673 for (i = 0, k = 0; i < fpdim; ++i) { 2674 PetscCall(PetscDualSpaceGetFunctional(Qref, i, &f)); 2675 PetscCall(PetscQuadratureGetData(f, NULL, &qNc, &Np, NULL, &qweights)); 2676 PetscCheck(qNc == NcJ, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of components in quadrature %" PetscInt_FMT " does not match coarse field %" PetscInt_FMT, qNc, NcJ); 2677 for (p = 0; p < Np; ++p, ++k) { 2678 for (j = 0; j < cpdim; ++j) { 2679 for (c = 0; c < Nc; ++c) elemMat[(offsetI + i) * cTotDim + offsetJ + j] += 1.0 * qweights[p * qNc + c]; 2680 } 2681 } 2682 } 2683 } 2684 } 2685 offsetJ += cpdim; 2686 } 2687 offsetI += fpdim; 2688 PetscCall(PetscFree(points)); 2689 } 2690 if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(0, name, rTotDim, cTotDim, elemMat)); 2691 /* Preallocate matrix */ 2692 { 2693 Mat preallocator; 2694 PetscScalar *vals; 2695 PetscInt *cellCIndices, *cellFIndices; 2696 PetscInt locRows, locCols, cell; 2697 2698 PetscCall(MatGetLocalSize(In, &locRows, &locCols)); 2699 PetscCall(MatCreate(PetscObjectComm((PetscObject)In), &preallocator)); 2700 PetscCall(MatSetType(preallocator, MATPREALLOCATOR)); 2701 PetscCall(MatSetSizes(preallocator, locRows, locCols, PETSC_DETERMINE, PETSC_DETERMINE)); 2702 PetscCall(MatSetUp(preallocator)); 2703 PetscCall(PetscCalloc3(rTotDim * cTotDim, &vals, cTotDim, &cellCIndices, rTotDim, &cellFIndices)); 2704 for (cell = cStart; cell < cEnd; ++cell) { 2705 if (isRefined) { 2706 PetscCall(DMPlexMatGetClosureIndicesRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, cell, cellCIndices, cellFIndices)); 2707 PetscCall(MatSetValues(preallocator, rTotDim, cellFIndices, cTotDim, cellCIndices, vals, INSERT_VALUES)); 2708 } else { 2709 PetscCall(DMPlexMatSetClosureGeneral(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, preallocator, cell, vals, INSERT_VALUES)); 2710 } 2711 } 2712 PetscCall(PetscFree3(vals, cellCIndices, cellFIndices)); 2713 PetscCall(MatAssemblyBegin(preallocator, MAT_FINAL_ASSEMBLY)); 2714 PetscCall(MatAssemblyEnd(preallocator, MAT_FINAL_ASSEMBLY)); 2715 PetscCall(MatPreallocatorPreallocate(preallocator, PETSC_TRUE, In)); 2716 PetscCall(MatDestroy(&preallocator)); 2717 } 2718 /* Fill matrix */ 2719 PetscCall(MatZeroEntries(In)); 2720 for (c = cStart; c < cEnd; ++c) { 2721 if (isRefined) { 2722 PetscCall(DMPlexMatSetClosureRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, In, c, elemMat, INSERT_VALUES)); 2723 } else { 2724 PetscCall(DMPlexMatSetClosureGeneral(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, In, c, elemMat, INSERT_VALUES)); 2725 } 2726 } 2727 for (f = 0; f < Nf; ++f) PetscCall(PetscFEDestroy(&feRef[f])); 2728 PetscCall(PetscFree2(feRef, fvRef)); 2729 PetscCall(PetscFree(elemMat)); 2730 PetscCall(MatAssemblyBegin(In, MAT_FINAL_ASSEMBLY)); 2731 PetscCall(MatAssemblyEnd(In, MAT_FINAL_ASSEMBLY)); 2732 if (mesh->printFEM > 1) { 2733 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)In), "%s:\n", name)); 2734 PetscCall(MatChop(In, 1.0e-10)); 2735 PetscCall(MatView(In, NULL)); 2736 } 2737 PetscCall(PetscLogEventEnd(DMPLEX_InterpolatorFEM, dmc, dmf, 0, 0)); 2738 PetscFunctionReturn(PETSC_SUCCESS); 2739 } 2740 2741 PetscErrorCode DMPlexComputeMassMatrixNested(DM dmc, DM dmf, Mat mass, void *user) 2742 { 2743 SETERRQ(PetscObjectComm((PetscObject)dmc), PETSC_ERR_SUP, "Laziness"); 2744 } 2745 2746 /*@ 2747 DMPlexComputeInterpolatorGeneral - Form the local portion of the interpolation matrix I from the coarse `DM` to a non-nested fine `DM`. 2748 2749 Input Parameters: 2750 + dmf - The fine mesh 2751 . dmc - The coarse mesh 2752 - user - The user context 2753 2754 Output Parameter: 2755 . In - The interpolation matrix 2756 2757 Level: developer 2758 2759 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexComputeInterpolatorNested()`, `DMPlexComputeJacobianFEM()` 2760 @*/ 2761 PetscErrorCode DMPlexComputeInterpolatorGeneral(DM dmc, DM dmf, Mat In, void *user) 2762 { 2763 DM_Plex *mesh = (DM_Plex *)dmf->data; 2764 const char *name = "Interpolator"; 2765 PetscDS prob; 2766 Mat interp; 2767 PetscSection fsection, globalFSection; 2768 PetscSection csection, globalCSection; 2769 PetscInt locRows, locCols; 2770 PetscReal *x, *v0, *J, *invJ, detJ; 2771 PetscReal *v0c, *Jc, *invJc, detJc; 2772 PetscScalar *elemMat; 2773 PetscInt dim, Nf, field, totDim, cStart, cEnd, cell, ccell, s; 2774 2775 PetscFunctionBegin; 2776 PetscCall(PetscLogEventBegin(DMPLEX_InterpolatorFEM, dmc, dmf, 0, 0)); 2777 PetscCall(DMGetCoordinateDim(dmc, &dim)); 2778 PetscCall(DMGetDS(dmc, &prob)); 2779 PetscCall(PetscDSGetWorkspace(prob, &x, NULL, NULL, NULL, NULL)); 2780 PetscCall(PetscDSGetNumFields(prob, &Nf)); 2781 PetscCall(PetscMalloc3(dim, &v0, dim * dim, &J, dim * dim, &invJ)); 2782 PetscCall(PetscMalloc3(dim, &v0c, dim * dim, &Jc, dim * dim, &invJc)); 2783 PetscCall(DMGetLocalSection(dmf, &fsection)); 2784 PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 2785 PetscCall(DMGetLocalSection(dmc, &csection)); 2786 PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 2787 PetscCall(DMPlexGetSimplexOrBoxCells(dmf, 0, &cStart, &cEnd)); 2788 PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 2789 PetscCall(PetscMalloc1(totDim, &elemMat)); 2790 2791 PetscCall(MatGetLocalSize(In, &locRows, &locCols)); 2792 PetscCall(MatCreate(PetscObjectComm((PetscObject)In), &interp)); 2793 PetscCall(MatSetType(interp, MATPREALLOCATOR)); 2794 PetscCall(MatSetSizes(interp, locRows, locCols, PETSC_DETERMINE, PETSC_DETERMINE)); 2795 PetscCall(MatSetUp(interp)); 2796 for (s = 0; s < 2; ++s) { 2797 for (field = 0; field < Nf; ++field) { 2798 PetscObject obj; 2799 PetscClassId id; 2800 PetscDualSpace Q = NULL; 2801 PetscTabulation T = NULL; 2802 PetscQuadrature f; 2803 const PetscReal *qpoints, *qweights; 2804 PetscInt Nc, qNc, Np, fpdim, off, i, d; 2805 2806 PetscCall(PetscDSGetFieldOffset(prob, field, &off)); 2807 PetscCall(PetscDSGetDiscretization(prob, field, &obj)); 2808 PetscCall(PetscObjectGetClassId(obj, &id)); 2809 if (id == PETSCFE_CLASSID) { 2810 PetscFE fe = (PetscFE)obj; 2811 2812 PetscCall(PetscFEGetDualSpace(fe, &Q)); 2813 PetscCall(PetscFEGetNumComponents(fe, &Nc)); 2814 if (s) PetscCall(PetscFECreateTabulation(fe, 1, 1, x, 0, &T)); 2815 } else if (id == PETSCFV_CLASSID) { 2816 PetscFV fv = (PetscFV)obj; 2817 2818 PetscCall(PetscFVGetDualSpace(fv, &Q)); 2819 Nc = 1; 2820 } else SETERRQ(PetscObjectComm((PetscObject)dmc), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 2821 PetscCall(PetscDualSpaceGetDimension(Q, &fpdim)); 2822 /* For each fine grid cell */ 2823 for (cell = cStart; cell < cEnd; ++cell) { 2824 PetscInt *findices, *cindices; 2825 PetscInt numFIndices, numCIndices; 2826 2827 PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 2828 PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ)); 2829 PetscCheck(numFIndices == totDim, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fine indices %" PetscInt_FMT " != %" PetscInt_FMT " dual basis vecs", numFIndices, totDim); 2830 for (i = 0; i < fpdim; ++i) { 2831 Vec pointVec; 2832 PetscScalar *pV; 2833 PetscSF coarseCellSF = NULL; 2834 const PetscSFNode *coarseCells; 2835 PetscInt numCoarseCells, cpdim, row = findices[i + off], q, c, j; 2836 2837 /* Get points from the dual basis functional quadrature */ 2838 PetscCall(PetscDualSpaceGetFunctional(Q, i, &f)); 2839 PetscCall(PetscQuadratureGetData(f, NULL, &qNc, &Np, &qpoints, &qweights)); 2840 PetscCheck(qNc == Nc, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of components in quadrature %" PetscInt_FMT " does not match coarse field %" PetscInt_FMT, qNc, Nc); 2841 PetscCall(VecCreateSeq(PETSC_COMM_SELF, Np * dim, &pointVec)); 2842 PetscCall(VecSetBlockSize(pointVec, dim)); 2843 PetscCall(VecGetArray(pointVec, &pV)); 2844 for (q = 0; q < Np; ++q) { 2845 const PetscReal xi0[3] = {-1., -1., -1.}; 2846 2847 /* Transform point to real space */ 2848 CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q * dim], x); 2849 for (d = 0; d < dim; ++d) pV[q * dim + d] = x[d]; 2850 } 2851 PetscCall(VecRestoreArray(pointVec, &pV)); 2852 /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */ 2853 /* OPT: Read this out from preallocation information */ 2854 PetscCall(DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF)); 2855 /* Update preallocation info */ 2856 PetscCall(PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells)); 2857 PetscCheck(numCoarseCells == Np, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Not all closure points located"); 2858 PetscCall(VecGetArray(pointVec, &pV)); 2859 for (ccell = 0; ccell < numCoarseCells; ++ccell) { 2860 PetscReal pVReal[3]; 2861 const PetscReal xi0[3] = {-1., -1., -1.}; 2862 2863 PetscCall(DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 2864 if (id == PETSCFE_CLASSID) PetscCall(PetscFEGetDimension((PetscFE)obj, &cpdim)); 2865 else cpdim = 1; 2866 2867 if (s) { 2868 /* Transform points from real space to coarse reference space */ 2869 PetscCall(DMPlexComputeCellGeometryFEM(dmc, coarseCells[ccell].index, NULL, v0c, Jc, invJc, &detJc)); 2870 for (d = 0; d < dim; ++d) pVReal[d] = PetscRealPart(pV[ccell * dim + d]); 2871 CoordinatesRealToRef(dim, dim, xi0, v0c, invJc, pVReal, x); 2872 2873 if (id == PETSCFE_CLASSID) { 2874 /* Evaluate coarse basis on contained point */ 2875 PetscCall(PetscFEComputeTabulation((PetscFE)obj, 1, x, 0, T)); 2876 PetscCall(PetscArrayzero(elemMat, cpdim)); 2877 /* Get elemMat entries by multiplying by weight */ 2878 for (j = 0; j < cpdim; ++j) { 2879 for (c = 0; c < Nc; ++c) elemMat[j] += T->T[0][j * Nc + c] * qweights[ccell * qNc + c]; 2880 } 2881 } else { 2882 for (j = 0; j < cpdim; ++j) { 2883 for (c = 0; c < Nc; ++c) elemMat[j] += 1.0 * qweights[ccell * qNc + c]; 2884 } 2885 } 2886 if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat)); 2887 } 2888 /* Update interpolator */ 2889 PetscCheck(numCIndices == totDim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %" PetscInt_FMT " != %" PetscInt_FMT, numCIndices, totDim); 2890 PetscCall(MatSetValues(interp, 1, &row, cpdim, &cindices[off], elemMat, INSERT_VALUES)); 2891 PetscCall(DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 2892 } 2893 PetscCall(VecRestoreArray(pointVec, &pV)); 2894 PetscCall(PetscSFDestroy(&coarseCellSF)); 2895 PetscCall(VecDestroy(&pointVec)); 2896 } 2897 PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 2898 } 2899 if (s && id == PETSCFE_CLASSID) PetscCall(PetscTabulationDestroy(&T)); 2900 } 2901 if (!s) { 2902 PetscCall(MatAssemblyBegin(interp, MAT_FINAL_ASSEMBLY)); 2903 PetscCall(MatAssemblyEnd(interp, MAT_FINAL_ASSEMBLY)); 2904 PetscCall(MatPreallocatorPreallocate(interp, PETSC_TRUE, In)); 2905 PetscCall(MatDestroy(&interp)); 2906 interp = In; 2907 } 2908 } 2909 PetscCall(PetscFree3(v0, J, invJ)); 2910 PetscCall(PetscFree3(v0c, Jc, invJc)); 2911 PetscCall(PetscFree(elemMat)); 2912 PetscCall(MatAssemblyBegin(In, MAT_FINAL_ASSEMBLY)); 2913 PetscCall(MatAssemblyEnd(In, MAT_FINAL_ASSEMBLY)); 2914 PetscCall(PetscLogEventEnd(DMPLEX_InterpolatorFEM, dmc, dmf, 0, 0)); 2915 PetscFunctionReturn(PETSC_SUCCESS); 2916 } 2917 2918 /*@ 2919 DMPlexComputeMassMatrixGeneral - Form the local portion of the mass matrix M from the coarse `DM` to a non-nested fine `DM`. 2920 2921 Input Parameters: 2922 + dmf - The fine mesh 2923 . dmc - The coarse mesh 2924 - user - The user context 2925 2926 Output Parameter: 2927 . mass - The mass matrix 2928 2929 Level: developer 2930 2931 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexComputeMassMatrixNested()`, `DMPlexComputeInterpolatorNested()`, `DMPlexComputeInterpolatorGeneral()`, `DMPlexComputeJacobianFEM()` 2932 @*/ 2933 PetscErrorCode DMPlexComputeMassMatrixGeneral(DM dmc, DM dmf, Mat mass, void *user) 2934 { 2935 DM_Plex *mesh = (DM_Plex *)dmf->data; 2936 const char *name = "Mass Matrix"; 2937 PetscDS prob; 2938 PetscSection fsection, csection, globalFSection, globalCSection; 2939 PetscHSetIJ ht; 2940 PetscLayout rLayout; 2941 PetscInt *dnz, *onz; 2942 PetscInt locRows, rStart, rEnd; 2943 PetscReal *x, *v0, *J, *invJ, detJ; 2944 PetscReal *v0c, *Jc, *invJc, detJc; 2945 PetscScalar *elemMat; 2946 PetscInt dim, Nf, field, totDim, cStart, cEnd, cell, ccell; 2947 2948 PetscFunctionBegin; 2949 PetscCall(DMGetCoordinateDim(dmc, &dim)); 2950 PetscCall(DMGetDS(dmc, &prob)); 2951 PetscCall(PetscDSGetWorkspace(prob, &x, NULL, NULL, NULL, NULL)); 2952 PetscCall(PetscDSGetNumFields(prob, &Nf)); 2953 PetscCall(PetscMalloc3(dim, &v0, dim * dim, &J, dim * dim, &invJ)); 2954 PetscCall(PetscMalloc3(dim, &v0c, dim * dim, &Jc, dim * dim, &invJc)); 2955 PetscCall(DMGetLocalSection(dmf, &fsection)); 2956 PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 2957 PetscCall(DMGetLocalSection(dmc, &csection)); 2958 PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 2959 PetscCall(DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd)); 2960 PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 2961 PetscCall(PetscMalloc1(totDim, &elemMat)); 2962 2963 PetscCall(MatGetLocalSize(mass, &locRows, NULL)); 2964 PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject)mass), &rLayout)); 2965 PetscCall(PetscLayoutSetLocalSize(rLayout, locRows)); 2966 PetscCall(PetscLayoutSetBlockSize(rLayout, 1)); 2967 PetscCall(PetscLayoutSetUp(rLayout)); 2968 PetscCall(PetscLayoutGetRange(rLayout, &rStart, &rEnd)); 2969 PetscCall(PetscLayoutDestroy(&rLayout)); 2970 PetscCall(PetscCalloc2(locRows, &dnz, locRows, &onz)); 2971 PetscCall(PetscHSetIJCreate(&ht)); 2972 for (field = 0; field < Nf; ++field) { 2973 PetscObject obj; 2974 PetscClassId id; 2975 PetscQuadrature quad; 2976 const PetscReal *qpoints; 2977 PetscInt Nq, Nc, i, d; 2978 2979 PetscCall(PetscDSGetDiscretization(prob, field, &obj)); 2980 PetscCall(PetscObjectGetClassId(obj, &id)); 2981 if (id == PETSCFE_CLASSID) PetscCall(PetscFEGetQuadrature((PetscFE)obj, &quad)); 2982 else PetscCall(PetscFVGetQuadrature((PetscFV)obj, &quad)); 2983 PetscCall(PetscQuadratureGetData(quad, NULL, &Nc, &Nq, &qpoints, NULL)); 2984 /* For each fine grid cell */ 2985 for (cell = cStart; cell < cEnd; ++cell) { 2986 Vec pointVec; 2987 PetscScalar *pV; 2988 PetscSF coarseCellSF = NULL; 2989 const PetscSFNode *coarseCells; 2990 PetscInt numCoarseCells, q, c; 2991 PetscInt *findices, *cindices; 2992 PetscInt numFIndices, numCIndices; 2993 2994 PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 2995 PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ)); 2996 /* Get points from the quadrature */ 2997 PetscCall(VecCreateSeq(PETSC_COMM_SELF, Nq * dim, &pointVec)); 2998 PetscCall(VecSetBlockSize(pointVec, dim)); 2999 PetscCall(VecGetArray(pointVec, &pV)); 3000 for (q = 0; q < Nq; ++q) { 3001 const PetscReal xi0[3] = {-1., -1., -1.}; 3002 3003 /* Transform point to real space */ 3004 CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q * dim], x); 3005 for (d = 0; d < dim; ++d) pV[q * dim + d] = x[d]; 3006 } 3007 PetscCall(VecRestoreArray(pointVec, &pV)); 3008 /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */ 3009 PetscCall(DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF)); 3010 PetscCall(PetscSFViewFromOptions(coarseCellSF, NULL, "-interp_sf_view")); 3011 /* Update preallocation info */ 3012 PetscCall(PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells)); 3013 PetscCheck(numCoarseCells == Nq, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Not all closure points located"); 3014 { 3015 PetscHashIJKey key; 3016 PetscBool missing; 3017 3018 for (i = 0; i < numFIndices; ++i) { 3019 key.i = findices[i]; 3020 if (key.i >= 0) { 3021 /* Get indices for coarse elements */ 3022 for (ccell = 0; ccell < numCoarseCells; ++ccell) { 3023 PetscCall(DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 3024 for (c = 0; c < numCIndices; ++c) { 3025 key.j = cindices[c]; 3026 if (key.j < 0) continue; 3027 PetscCall(PetscHSetIJQueryAdd(ht, key, &missing)); 3028 if (missing) { 3029 if ((key.j >= rStart) && (key.j < rEnd)) ++dnz[key.i - rStart]; 3030 else ++onz[key.i - rStart]; 3031 } 3032 } 3033 PetscCall(DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 3034 } 3035 } 3036 } 3037 } 3038 PetscCall(PetscSFDestroy(&coarseCellSF)); 3039 PetscCall(VecDestroy(&pointVec)); 3040 PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 3041 } 3042 } 3043 PetscCall(PetscHSetIJDestroy(&ht)); 3044 PetscCall(MatXAIJSetPreallocation(mass, 1, dnz, onz, NULL, NULL)); 3045 PetscCall(MatSetOption(mass, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE)); 3046 PetscCall(PetscFree2(dnz, onz)); 3047 for (field = 0; field < Nf; ++field) { 3048 PetscObject obj; 3049 PetscClassId id; 3050 PetscTabulation T, Tfine; 3051 PetscQuadrature quad; 3052 const PetscReal *qpoints, *qweights; 3053 PetscInt Nq, Nc, i, d; 3054 3055 PetscCall(PetscDSGetDiscretization(prob, field, &obj)); 3056 PetscCall(PetscObjectGetClassId(obj, &id)); 3057 if (id == PETSCFE_CLASSID) { 3058 PetscCall(PetscFEGetQuadrature((PetscFE)obj, &quad)); 3059 PetscCall(PetscFEGetCellTabulation((PetscFE)obj, 1, &Tfine)); 3060 PetscCall(PetscFECreateTabulation((PetscFE)obj, 1, 1, x, 0, &T)); 3061 } else { 3062 PetscCall(PetscFVGetQuadrature((PetscFV)obj, &quad)); 3063 } 3064 PetscCall(PetscQuadratureGetData(quad, NULL, &Nc, &Nq, &qpoints, &qweights)); 3065 /* For each fine grid cell */ 3066 for (cell = cStart; cell < cEnd; ++cell) { 3067 Vec pointVec; 3068 PetscScalar *pV; 3069 PetscSF coarseCellSF = NULL; 3070 const PetscSFNode *coarseCells; 3071 PetscInt numCoarseCells, cpdim, q, c, j; 3072 PetscInt *findices, *cindices; 3073 PetscInt numFIndices, numCIndices; 3074 3075 PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 3076 PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ)); 3077 /* Get points from the quadrature */ 3078 PetscCall(VecCreateSeq(PETSC_COMM_SELF, Nq * dim, &pointVec)); 3079 PetscCall(VecSetBlockSize(pointVec, dim)); 3080 PetscCall(VecGetArray(pointVec, &pV)); 3081 for (q = 0; q < Nq; ++q) { 3082 const PetscReal xi0[3] = {-1., -1., -1.}; 3083 3084 /* Transform point to real space */ 3085 CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q * dim], x); 3086 for (d = 0; d < dim; ++d) pV[q * dim + d] = x[d]; 3087 } 3088 PetscCall(VecRestoreArray(pointVec, &pV)); 3089 /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */ 3090 PetscCall(DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF)); 3091 /* Update matrix */ 3092 PetscCall(PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells)); 3093 PetscCheck(numCoarseCells == Nq, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Not all closure points located"); 3094 PetscCall(VecGetArray(pointVec, &pV)); 3095 for (ccell = 0; ccell < numCoarseCells; ++ccell) { 3096 PetscReal pVReal[3]; 3097 const PetscReal xi0[3] = {-1., -1., -1.}; 3098 3099 PetscCall(DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 3100 /* Transform points from real space to coarse reference space */ 3101 PetscCall(DMPlexComputeCellGeometryFEM(dmc, coarseCells[ccell].index, NULL, v0c, Jc, invJc, &detJc)); 3102 for (d = 0; d < dim; ++d) pVReal[d] = PetscRealPart(pV[ccell * dim + d]); 3103 CoordinatesRealToRef(dim, dim, xi0, v0c, invJc, pVReal, x); 3104 3105 if (id == PETSCFE_CLASSID) { 3106 PetscFE fe = (PetscFE)obj; 3107 3108 /* Evaluate coarse basis on contained point */ 3109 PetscCall(PetscFEGetDimension(fe, &cpdim)); 3110 PetscCall(PetscFEComputeTabulation(fe, 1, x, 0, T)); 3111 /* Get elemMat entries by multiplying by weight */ 3112 for (i = 0; i < numFIndices; ++i) { 3113 PetscCall(PetscArrayzero(elemMat, cpdim)); 3114 for (j = 0; j < cpdim; ++j) { 3115 for (c = 0; c < Nc; ++c) elemMat[j] += T->T[0][j * Nc + c] * Tfine->T[0][(ccell * numFIndices + i) * Nc + c] * qweights[ccell * Nc + c] * detJ; 3116 } 3117 /* Update interpolator */ 3118 if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat)); 3119 PetscCheck(numCIndices == cpdim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %" PetscInt_FMT " != %" PetscInt_FMT, numCIndices, cpdim); 3120 PetscCall(MatSetValues(mass, 1, &findices[i], numCIndices, cindices, elemMat, ADD_VALUES)); 3121 } 3122 } else { 3123 cpdim = 1; 3124 for (i = 0; i < numFIndices; ++i) { 3125 PetscCall(PetscArrayzero(elemMat, cpdim)); 3126 for (j = 0; j < cpdim; ++j) { 3127 for (c = 0; c < Nc; ++c) elemMat[j] += 1.0 * 1.0 * qweights[ccell * Nc + c] * detJ; 3128 } 3129 /* Update interpolator */ 3130 if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat)); 3131 PetscCall(PetscPrintf(PETSC_COMM_SELF, "Nq: %" PetscInt_FMT " %" PetscInt_FMT " Nf: %" PetscInt_FMT " %" PetscInt_FMT " Nc: %" PetscInt_FMT " %" PetscInt_FMT "\n", ccell, Nq, i, numFIndices, j, numCIndices)); 3132 PetscCheck(numCIndices == cpdim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %" PetscInt_FMT " != %" PetscInt_FMT, numCIndices, cpdim); 3133 PetscCall(MatSetValues(mass, 1, &findices[i], numCIndices, cindices, elemMat, ADD_VALUES)); 3134 } 3135 } 3136 PetscCall(DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 3137 } 3138 PetscCall(VecRestoreArray(pointVec, &pV)); 3139 PetscCall(PetscSFDestroy(&coarseCellSF)); 3140 PetscCall(VecDestroy(&pointVec)); 3141 PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 3142 } 3143 if (id == PETSCFE_CLASSID) PetscCall(PetscTabulationDestroy(&T)); 3144 } 3145 PetscCall(PetscFree3(v0, J, invJ)); 3146 PetscCall(PetscFree3(v0c, Jc, invJc)); 3147 PetscCall(PetscFree(elemMat)); 3148 PetscCall(MatAssemblyBegin(mass, MAT_FINAL_ASSEMBLY)); 3149 PetscCall(MatAssemblyEnd(mass, MAT_FINAL_ASSEMBLY)); 3150 PetscFunctionReturn(PETSC_SUCCESS); 3151 } 3152 3153 /*@ 3154 DMPlexComputeInjectorFEM - Compute a mapping from coarse unknowns to fine unknowns 3155 3156 Input Parameters: 3157 + dmc - The coarse mesh 3158 - dmf - The fine mesh 3159 - user - The user context 3160 3161 Output Parameter: 3162 . sc - The mapping 3163 3164 Level: developer 3165 3166 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexComputeInterpolatorNested()`, `DMPlexComputeJacobianFEM()` 3167 @*/ 3168 PetscErrorCode DMPlexComputeInjectorFEM(DM dmc, DM dmf, VecScatter *sc, void *user) 3169 { 3170 PetscDS prob; 3171 PetscFE *feRef; 3172 PetscFV *fvRef; 3173 Vec fv, cv; 3174 IS fis, cis; 3175 PetscSection fsection, fglobalSection, csection, cglobalSection; 3176 PetscInt *cmap, *cellCIndices, *cellFIndices, *cindices, *findices; 3177 PetscInt cTotDim, fTotDim = 0, Nf, f, field, cStart, cEnd, c, dim, d, startC, endC, offsetC, offsetF, m; 3178 PetscBool *needAvg; 3179 3180 PetscFunctionBegin; 3181 PetscCall(PetscLogEventBegin(DMPLEX_InjectorFEM, dmc, dmf, 0, 0)); 3182 PetscCall(DMGetDimension(dmf, &dim)); 3183 PetscCall(DMGetLocalSection(dmf, &fsection)); 3184 PetscCall(DMGetGlobalSection(dmf, &fglobalSection)); 3185 PetscCall(DMGetLocalSection(dmc, &csection)); 3186 PetscCall(DMGetGlobalSection(dmc, &cglobalSection)); 3187 PetscCall(PetscSectionGetNumFields(fsection, &Nf)); 3188 PetscCall(DMPlexGetSimplexOrBoxCells(dmc, 0, &cStart, &cEnd)); 3189 PetscCall(DMGetDS(dmc, &prob)); 3190 PetscCall(PetscCalloc3(Nf, &feRef, Nf, &fvRef, Nf, &needAvg)); 3191 for (f = 0; f < Nf; ++f) { 3192 PetscObject obj; 3193 PetscClassId id; 3194 PetscInt fNb = 0, Nc = 0; 3195 3196 PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 3197 PetscCall(PetscObjectGetClassId(obj, &id)); 3198 if (id == PETSCFE_CLASSID) { 3199 PetscFE fe = (PetscFE)obj; 3200 PetscSpace sp; 3201 PetscInt maxDegree; 3202 3203 PetscCall(PetscFERefine(fe, &feRef[f])); 3204 PetscCall(PetscFEGetDimension(feRef[f], &fNb)); 3205 PetscCall(PetscFEGetNumComponents(fe, &Nc)); 3206 PetscCall(PetscFEGetBasisSpace(fe, &sp)); 3207 PetscCall(PetscSpaceGetDegree(sp, NULL, &maxDegree)); 3208 if (!maxDegree) needAvg[f] = PETSC_TRUE; 3209 } else if (id == PETSCFV_CLASSID) { 3210 PetscFV fv = (PetscFV)obj; 3211 PetscDualSpace Q; 3212 3213 PetscCall(PetscFVRefine(fv, &fvRef[f])); 3214 PetscCall(PetscFVGetDualSpace(fvRef[f], &Q)); 3215 PetscCall(PetscDualSpaceGetDimension(Q, &fNb)); 3216 PetscCall(PetscFVGetNumComponents(fv, &Nc)); 3217 needAvg[f] = PETSC_TRUE; 3218 } 3219 fTotDim += fNb; 3220 } 3221 PetscCall(PetscDSGetTotalDimension(prob, &cTotDim)); 3222 PetscCall(PetscMalloc1(cTotDim, &cmap)); 3223 for (field = 0, offsetC = 0, offsetF = 0; field < Nf; ++field) { 3224 PetscFE feC; 3225 PetscFV fvC; 3226 PetscDualSpace QF, QC; 3227 PetscInt order = -1, NcF, NcC, fpdim, cpdim; 3228 3229 if (feRef[field]) { 3230 PetscCall(PetscDSGetDiscretization(prob, field, (PetscObject *)&feC)); 3231 PetscCall(PetscFEGetNumComponents(feC, &NcC)); 3232 PetscCall(PetscFEGetNumComponents(feRef[field], &NcF)); 3233 PetscCall(PetscFEGetDualSpace(feRef[field], &QF)); 3234 PetscCall(PetscDualSpaceGetOrder(QF, &order)); 3235 PetscCall(PetscDualSpaceGetDimension(QF, &fpdim)); 3236 PetscCall(PetscFEGetDualSpace(feC, &QC)); 3237 PetscCall(PetscDualSpaceGetDimension(QC, &cpdim)); 3238 } else { 3239 PetscCall(PetscDSGetDiscretization(prob, field, (PetscObject *)&fvC)); 3240 PetscCall(PetscFVGetNumComponents(fvC, &NcC)); 3241 PetscCall(PetscFVGetNumComponents(fvRef[field], &NcF)); 3242 PetscCall(PetscFVGetDualSpace(fvRef[field], &QF)); 3243 PetscCall(PetscDualSpaceGetDimension(QF, &fpdim)); 3244 PetscCall(PetscFVGetDualSpace(fvC, &QC)); 3245 PetscCall(PetscDualSpaceGetDimension(QC, &cpdim)); 3246 } 3247 PetscCheck(NcF == NcC, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of components in fine space field %" PetscInt_FMT " does not match coarse field %" PetscInt_FMT, NcF, NcC); 3248 for (c = 0; c < cpdim; ++c) { 3249 PetscQuadrature cfunc; 3250 const PetscReal *cqpoints, *cqweights; 3251 PetscInt NqcC, NpC; 3252 PetscBool found = PETSC_FALSE; 3253 3254 PetscCall(PetscDualSpaceGetFunctional(QC, c, &cfunc)); 3255 PetscCall(PetscQuadratureGetData(cfunc, NULL, &NqcC, &NpC, &cqpoints, &cqweights)); 3256 PetscCheck(NqcC == NcC, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of quadrature components %" PetscInt_FMT " must match number of field components %" PetscInt_FMT, NqcC, NcC); 3257 PetscCheck(NpC == 1 || !feRef[field], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Do not know how to do injection for moments"); 3258 for (f = 0; f < fpdim; ++f) { 3259 PetscQuadrature ffunc; 3260 const PetscReal *fqpoints, *fqweights; 3261 PetscReal sum = 0.0; 3262 PetscInt NqcF, NpF; 3263 3264 PetscCall(PetscDualSpaceGetFunctional(QF, f, &ffunc)); 3265 PetscCall(PetscQuadratureGetData(ffunc, NULL, &NqcF, &NpF, &fqpoints, &fqweights)); 3266 PetscCheck(NqcF == NcF, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of quadrature components %" PetscInt_FMT " must match number of field components %" PetscInt_FMT, NqcF, NcF); 3267 if (NpC != NpF) continue; 3268 for (d = 0; d < dim; ++d) sum += PetscAbsReal(cqpoints[d] - fqpoints[d]); 3269 if (sum > 1.0e-9) continue; 3270 for (d = 0; d < NcC; ++d) sum += PetscAbsReal(cqweights[d] * fqweights[d]); 3271 if (sum < 1.0e-9) continue; 3272 cmap[offsetC + c] = offsetF + f; 3273 found = PETSC_TRUE; 3274 break; 3275 } 3276 if (!found) { 3277 /* TODO We really want the average here, but some asshole put VecScatter in the interface */ 3278 if (fvRef[field] || (feRef[field] && order == 0)) { 3279 cmap[offsetC + c] = offsetF + 0; 3280 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate matching functional for injection"); 3281 } 3282 } 3283 offsetC += cpdim; 3284 offsetF += fpdim; 3285 } 3286 for (f = 0; f < Nf; ++f) { 3287 PetscCall(PetscFEDestroy(&feRef[f])); 3288 PetscCall(PetscFVDestroy(&fvRef[f])); 3289 } 3290 PetscCall(PetscFree3(feRef, fvRef, needAvg)); 3291 3292 PetscCall(DMGetGlobalVector(dmf, &fv)); 3293 PetscCall(DMGetGlobalVector(dmc, &cv)); 3294 PetscCall(VecGetOwnershipRange(cv, &startC, &endC)); 3295 PetscCall(PetscSectionGetConstrainedStorageSize(cglobalSection, &m)); 3296 PetscCall(PetscMalloc2(cTotDim, &cellCIndices, fTotDim, &cellFIndices)); 3297 PetscCall(PetscMalloc1(m, &cindices)); 3298 PetscCall(PetscMalloc1(m, &findices)); 3299 for (d = 0; d < m; ++d) cindices[d] = findices[d] = -1; 3300 for (c = cStart; c < cEnd; ++c) { 3301 PetscCall(DMPlexMatGetClosureIndicesRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, c, cellCIndices, cellFIndices)); 3302 for (d = 0; d < cTotDim; ++d) { 3303 if ((cellCIndices[d] < startC) || (cellCIndices[d] >= endC)) continue; 3304 PetscCheck(!(findices[cellCIndices[d] - startC] >= 0) || !(findices[cellCIndices[d] - startC] != cellFIndices[cmap[d]]), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Coarse dof %" PetscInt_FMT " maps to both %" PetscInt_FMT " and %" PetscInt_FMT, cindices[cellCIndices[d] - startC], findices[cellCIndices[d] - startC], cellFIndices[cmap[d]]); 3305 cindices[cellCIndices[d] - startC] = cellCIndices[d]; 3306 findices[cellCIndices[d] - startC] = cellFIndices[cmap[d]]; 3307 } 3308 } 3309 PetscCall(PetscFree(cmap)); 3310 PetscCall(PetscFree2(cellCIndices, cellFIndices)); 3311 3312 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, m, cindices, PETSC_OWN_POINTER, &cis)); 3313 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, m, findices, PETSC_OWN_POINTER, &fis)); 3314 PetscCall(VecScatterCreate(cv, cis, fv, fis, sc)); 3315 PetscCall(ISDestroy(&cis)); 3316 PetscCall(ISDestroy(&fis)); 3317 PetscCall(DMRestoreGlobalVector(dmf, &fv)); 3318 PetscCall(DMRestoreGlobalVector(dmc, &cv)); 3319 PetscCall(PetscLogEventEnd(DMPLEX_InjectorFEM, dmc, dmf, 0, 0)); 3320 PetscFunctionReturn(PETSC_SUCCESS); 3321 } 3322 3323 /*@C 3324 DMPlexGetCellFields - Retrieve the field values values for a chunk of cells 3325 3326 Input Parameters: 3327 + dm - The `DM` 3328 . cellIS - The cells to include 3329 . locX - A local vector with the solution fields 3330 . locX_t - A local vector with solution field time derivatives, or NULL 3331 - locA - A local vector with auxiliary fields, or NULL 3332 3333 Output Parameters: 3334 + u - The field coefficients 3335 . u_t - The fields derivative coefficients 3336 - a - The auxiliary field coefficients 3337 3338 Level: developer 3339 3340 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetFaceFields()` 3341 @*/ 3342 PetscErrorCode DMPlexGetCellFields(DM dm, IS cellIS, Vec locX, Vec locX_t, Vec locA, PetscScalar **u, PetscScalar **u_t, PetscScalar **a) 3343 { 3344 DM plex, plexA = NULL; 3345 DMEnclosureType encAux; 3346 PetscSection section, sectionAux; 3347 PetscDS prob; 3348 const PetscInt *cells; 3349 PetscInt cStart, cEnd, numCells, totDim, totDimAux, c; 3350 3351 PetscFunctionBegin; 3352 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3353 PetscValidHeaderSpecific(locX, VEC_CLASSID, 3); 3354 if (locX_t) PetscValidHeaderSpecific(locX_t, VEC_CLASSID, 4); 3355 if (locA) PetscValidHeaderSpecific(locA, VEC_CLASSID, 5); 3356 PetscValidPointer(u, 6); 3357 PetscValidPointer(u_t, 7); 3358 PetscValidPointer(a, 8); 3359 PetscCall(DMPlexConvertPlex(dm, &plex, PETSC_FALSE)); 3360 PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 3361 PetscCall(DMGetLocalSection(dm, §ion)); 3362 PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob)); 3363 PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 3364 if (locA) { 3365 DM dmAux; 3366 PetscDS probAux; 3367 3368 PetscCall(VecGetDM(locA, &dmAux)); 3369 PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 3370 PetscCall(DMPlexConvertPlex(dmAux, &plexA, PETSC_FALSE)); 3371 PetscCall(DMGetLocalSection(dmAux, §ionAux)); 3372 PetscCall(DMGetDS(dmAux, &probAux)); 3373 PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 3374 } 3375 numCells = cEnd - cStart; 3376 PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, u)); 3377 if (locX_t) PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, u_t)); 3378 else *u_t = NULL; 3379 if (locA) PetscCall(DMGetWorkArray(dm, numCells * totDimAux, MPIU_SCALAR, a)); 3380 else *a = NULL; 3381 for (c = cStart; c < cEnd; ++c) { 3382 const PetscInt cell = cells ? cells[c] : c; 3383 const PetscInt cind = c - cStart; 3384 PetscScalar *x = NULL, *x_t = NULL, *ul = *u, *ul_t = *u_t, *al = *a; 3385 PetscInt i; 3386 3387 PetscCall(DMPlexVecGetClosure(plex, section, locX, cell, NULL, &x)); 3388 for (i = 0; i < totDim; ++i) ul[cind * totDim + i] = x[i]; 3389 PetscCall(DMPlexVecRestoreClosure(plex, section, locX, cell, NULL, &x)); 3390 if (locX_t) { 3391 PetscCall(DMPlexVecGetClosure(plex, section, locX_t, cell, NULL, &x_t)); 3392 for (i = 0; i < totDim; ++i) ul_t[cind * totDim + i] = x_t[i]; 3393 PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, cell, NULL, &x_t)); 3394 } 3395 if (locA) { 3396 PetscInt subcell; 3397 PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, cell, &subcell)); 3398 PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subcell, NULL, &x)); 3399 for (i = 0; i < totDimAux; ++i) al[cind * totDimAux + i] = x[i]; 3400 PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subcell, NULL, &x)); 3401 } 3402 } 3403 PetscCall(DMDestroy(&plex)); 3404 if (locA) PetscCall(DMDestroy(&plexA)); 3405 PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 3406 PetscFunctionReturn(PETSC_SUCCESS); 3407 } 3408 3409 /*@C 3410 DMPlexRestoreCellFields - Restore the field values values for a chunk of cells 3411 3412 Input Parameters: 3413 + dm - The `DM` 3414 . cellIS - The cells to include 3415 . locX - A local vector with the solution fields 3416 . locX_t - A local vector with solution field time derivatives, or NULL 3417 - locA - A local vector with auxiliary fields, or NULL 3418 3419 Output Parameters: 3420 + u - The field coefficients 3421 . u_t - The fields derivative coefficients 3422 - a - The auxiliary field coefficients 3423 3424 Level: developer 3425 3426 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetFaceFields()` 3427 @*/ 3428 PetscErrorCode DMPlexRestoreCellFields(DM dm, IS cellIS, Vec locX, Vec locX_t, Vec locA, PetscScalar **u, PetscScalar **u_t, PetscScalar **a) 3429 { 3430 PetscFunctionBegin; 3431 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, u)); 3432 if (locX_t) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, u_t)); 3433 if (locA) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, a)); 3434 PetscFunctionReturn(PETSC_SUCCESS); 3435 } 3436 3437 /* 3438 Get the auxiliary field vectors for the negative side (s = 0) and positive side (s = 1) of the interfaace 3439 */ 3440 static PetscErrorCode DMPlexGetHybridAuxFields(DM dm, DM dmAux[], PetscDS dsAux[], IS cellIS, Vec locA[], PetscScalar *a[]) 3441 { 3442 DM plexA[2]; 3443 DMEnclosureType encAux[2]; 3444 PetscSection sectionAux[2]; 3445 const PetscInt *cells; 3446 PetscInt cStart, cEnd, numCells, c, s, totDimAux[2]; 3447 3448 PetscFunctionBegin; 3449 PetscValidPointer(locA, 5); 3450 if (!locA[0] || !locA[1]) PetscFunctionReturn(PETSC_SUCCESS); 3451 PetscValidPointer(dmAux, 2); 3452 PetscValidPointer(dsAux, 3); 3453 PetscValidPointer(a, 6); 3454 PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 3455 numCells = cEnd - cStart; 3456 for (s = 0; s < 2; ++s) { 3457 PetscValidHeaderSpecific(dmAux[s], DM_CLASSID, 2); 3458 PetscValidHeaderSpecific(dsAux[s], PETSCDS_CLASSID, 3); 3459 PetscValidHeaderSpecific(locA[s], VEC_CLASSID, 5); 3460 PetscCall(DMPlexConvertPlex(dmAux[s], &plexA[s], PETSC_FALSE)); 3461 PetscCall(DMGetEnclosureRelation(dmAux[s], dm, &encAux[s])); 3462 PetscCall(DMGetLocalSection(dmAux[s], §ionAux[s])); 3463 PetscCall(PetscDSGetTotalDimension(dsAux[s], &totDimAux[s])); 3464 PetscCall(DMGetWorkArray(dmAux[s], numCells * totDimAux[s], MPIU_SCALAR, &a[s])); 3465 } 3466 for (c = cStart; c < cEnd; ++c) { 3467 const PetscInt cell = cells ? cells[c] : c; 3468 const PetscInt cind = c - cStart; 3469 const PetscInt *cone, *ornt; 3470 3471 PetscCall(DMPlexGetCone(dm, cell, &cone)); 3472 PetscCall(DMPlexGetConeOrientation(dm, cell, &ornt)); 3473 for (s = 0; s < 2; ++s) { 3474 const PetscInt *support; 3475 PetscScalar *x = NULL, *al = a[s]; 3476 const PetscInt tdA = totDimAux[s]; 3477 PetscInt ssize, scell; 3478 PetscInt subface, Na, i; 3479 3480 PetscCall(DMPlexGetSupport(dm, cone[s], &support)); 3481 PetscCall(DMPlexGetSupportSize(dm, cone[s], &ssize)); 3482 PetscCheck(ssize == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " from cell %" PetscInt_FMT " has support size %" PetscInt_FMT " != 2", cone[s], cell, ssize); 3483 if (support[0] == cell) scell = support[1]; 3484 else if (support[1] == cell) scell = support[0]; 3485 else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " does not have cell %" PetscInt_FMT " in its support", cone[s], cell); 3486 3487 PetscCall(DMGetEnclosurePoint(plexA[s], dm, encAux[s], scell, &subface)); 3488 PetscCall(DMPlexVecGetClosure(plexA[s], sectionAux[s], locA[s], subface, &Na, &x)); 3489 for (i = 0; i < Na; ++i) al[cind * tdA + i] = x[i]; 3490 PetscCall(DMPlexVecRestoreClosure(plexA[s], sectionAux[s], locA[s], subface, &Na, &x)); 3491 } 3492 } 3493 for (s = 0; s < 2; ++s) PetscCall(DMDestroy(&plexA[s])); 3494 PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 3495 PetscFunctionReturn(PETSC_SUCCESS); 3496 } 3497 3498 static PetscErrorCode DMPlexRestoreHybridAuxFields(DM dmAux[], PetscDS dsAux[], IS cellIS, Vec locA[], PetscScalar *a[]) 3499 { 3500 PetscFunctionBegin; 3501 if (!locA[0] || !locA[1]) PetscFunctionReturn(PETSC_SUCCESS); 3502 PetscCall(DMRestoreWorkArray(dmAux[0], 0, MPIU_SCALAR, &a[0])); 3503 PetscCall(DMRestoreWorkArray(dmAux[1], 0, MPIU_SCALAR, &a[1])); 3504 PetscFunctionReturn(PETSC_SUCCESS); 3505 } 3506 3507 /*@C 3508 DMPlexGetFaceFields - Retrieve the field values values for a chunk of faces 3509 3510 Input Parameters: 3511 + dm - The `DM` 3512 . fStart - The first face to include 3513 . fEnd - The first face to exclude 3514 . locX - A local vector with the solution fields 3515 . locX_t - A local vector with solution field time derivatives, or NULL 3516 . faceGeometry - A local vector with face geometry 3517 . cellGeometry - A local vector with cell geometry 3518 - locaGrad - A local vector with field gradients, or NULL 3519 3520 Output Parameters: 3521 + Nface - The number of faces with field values 3522 . uL - The field values at the left side of the face 3523 - uR - The field values at the right side of the face 3524 3525 Level: developer 3526 3527 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellFields()` 3528 @*/ 3529 PetscErrorCode DMPlexGetFaceFields(DM dm, PetscInt fStart, PetscInt fEnd, Vec locX, Vec locX_t, Vec faceGeometry, Vec cellGeometry, Vec locGrad, PetscInt *Nface, PetscScalar **uL, PetscScalar **uR) 3530 { 3531 DM dmFace, dmCell, dmGrad = NULL; 3532 PetscSection section; 3533 PetscDS prob; 3534 DMLabel ghostLabel; 3535 const PetscScalar *facegeom, *cellgeom, *x, *lgrad; 3536 PetscBool *isFE; 3537 PetscInt dim, Nf, f, Nc, numFaces = fEnd - fStart, iface, face; 3538 3539 PetscFunctionBegin; 3540 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3541 PetscValidHeaderSpecific(locX, VEC_CLASSID, 4); 3542 if (locX_t) PetscValidHeaderSpecific(locX_t, VEC_CLASSID, 5); 3543 PetscValidHeaderSpecific(faceGeometry, VEC_CLASSID, 6); 3544 PetscValidHeaderSpecific(cellGeometry, VEC_CLASSID, 7); 3545 if (locGrad) PetscValidHeaderSpecific(locGrad, VEC_CLASSID, 8); 3546 PetscValidPointer(uL, 10); 3547 PetscValidPointer(uR, 11); 3548 PetscCall(DMGetDimension(dm, &dim)); 3549 PetscCall(DMGetDS(dm, &prob)); 3550 PetscCall(DMGetLocalSection(dm, §ion)); 3551 PetscCall(PetscDSGetNumFields(prob, &Nf)); 3552 PetscCall(PetscDSGetTotalComponents(prob, &Nc)); 3553 PetscCall(PetscMalloc1(Nf, &isFE)); 3554 for (f = 0; f < Nf; ++f) { 3555 PetscObject obj; 3556 PetscClassId id; 3557 3558 PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 3559 PetscCall(PetscObjectGetClassId(obj, &id)); 3560 if (id == PETSCFE_CLASSID) { 3561 isFE[f] = PETSC_TRUE; 3562 } else if (id == PETSCFV_CLASSID) { 3563 isFE[f] = PETSC_FALSE; 3564 } else { 3565 isFE[f] = PETSC_FALSE; 3566 } 3567 } 3568 PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 3569 PetscCall(VecGetArrayRead(locX, &x)); 3570 PetscCall(VecGetDM(faceGeometry, &dmFace)); 3571 PetscCall(VecGetArrayRead(faceGeometry, &facegeom)); 3572 PetscCall(VecGetDM(cellGeometry, &dmCell)); 3573 PetscCall(VecGetArrayRead(cellGeometry, &cellgeom)); 3574 if (locGrad) { 3575 PetscCall(VecGetDM(locGrad, &dmGrad)); 3576 PetscCall(VecGetArrayRead(locGrad, &lgrad)); 3577 } 3578 PetscCall(DMGetWorkArray(dm, numFaces * Nc, MPIU_SCALAR, uL)); 3579 PetscCall(DMGetWorkArray(dm, numFaces * Nc, MPIU_SCALAR, uR)); 3580 /* Right now just eat the extra work for FE (could make a cell loop) */ 3581 for (face = fStart, iface = 0; face < fEnd; ++face) { 3582 const PetscInt *cells; 3583 PetscFVFaceGeom *fg; 3584 PetscFVCellGeom *cgL, *cgR; 3585 PetscScalar *xL, *xR, *gL, *gR; 3586 PetscScalar *uLl = *uL, *uRl = *uR; 3587 PetscInt ghost, nsupp, nchild; 3588 3589 PetscCall(DMLabelGetValue(ghostLabel, face, &ghost)); 3590 PetscCall(DMPlexGetSupportSize(dm, face, &nsupp)); 3591 PetscCall(DMPlexGetTreeChildren(dm, face, &nchild, NULL)); 3592 if (ghost >= 0 || nsupp > 2 || nchild > 0) continue; 3593 PetscCall(DMPlexPointLocalRead(dmFace, face, facegeom, &fg)); 3594 PetscCall(DMPlexGetSupport(dm, face, &cells)); 3595 PetscCall(DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cgL)); 3596 PetscCall(DMPlexPointLocalRead(dmCell, cells[1], cellgeom, &cgR)); 3597 for (f = 0; f < Nf; ++f) { 3598 PetscInt off; 3599 3600 PetscCall(PetscDSGetComponentOffset(prob, f, &off)); 3601 if (isFE[f]) { 3602 const PetscInt *cone; 3603 PetscInt comp, coneSizeL, coneSizeR, faceLocL, faceLocR, ldof, rdof, d; 3604 3605 xL = xR = NULL; 3606 PetscCall(PetscSectionGetFieldComponents(section, f, &comp)); 3607 PetscCall(DMPlexVecGetClosure(dm, section, locX, cells[0], &ldof, (PetscScalar **)&xL)); 3608 PetscCall(DMPlexVecGetClosure(dm, section, locX, cells[1], &rdof, (PetscScalar **)&xR)); 3609 PetscCall(DMPlexGetCone(dm, cells[0], &cone)); 3610 PetscCall(DMPlexGetConeSize(dm, cells[0], &coneSizeL)); 3611 for (faceLocL = 0; faceLocL < coneSizeL; ++faceLocL) 3612 if (cone[faceLocL] == face) break; 3613 PetscCall(DMPlexGetCone(dm, cells[1], &cone)); 3614 PetscCall(DMPlexGetConeSize(dm, cells[1], &coneSizeR)); 3615 for (faceLocR = 0; faceLocR < coneSizeR; ++faceLocR) 3616 if (cone[faceLocR] == face) break; 3617 PetscCheck(faceLocL != coneSizeL || faceLocR != coneSizeR, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %" PetscInt_FMT " in cone of cell %" PetscInt_FMT " or cell %" PetscInt_FMT, face, cells[0], cells[1]); 3618 /* Check that FEM field has values in the right cell (sometimes its an FV ghost cell) */ 3619 /* TODO: this is a hack that might not be right for nonconforming */ 3620 if (faceLocL < coneSizeL) { 3621 PetscCall(PetscFEEvaluateFaceFields_Internal(prob, f, faceLocL, xL, &uLl[iface * Nc + off])); 3622 if (rdof == ldof && faceLocR < coneSizeR) PetscCall(PetscFEEvaluateFaceFields_Internal(prob, f, faceLocR, xR, &uRl[iface * Nc + off])); 3623 else { 3624 for (d = 0; d < comp; ++d) uRl[iface * Nc + off + d] = uLl[iface * Nc + off + d]; 3625 } 3626 } else { 3627 PetscCall(PetscFEEvaluateFaceFields_Internal(prob, f, faceLocR, xR, &uRl[iface * Nc + off])); 3628 PetscCall(PetscSectionGetFieldComponents(section, f, &comp)); 3629 for (d = 0; d < comp; ++d) uLl[iface * Nc + off + d] = uRl[iface * Nc + off + d]; 3630 } 3631 PetscCall(DMPlexVecRestoreClosure(dm, section, locX, cells[0], &ldof, (PetscScalar **)&xL)); 3632 PetscCall(DMPlexVecRestoreClosure(dm, section, locX, cells[1], &rdof, (PetscScalar **)&xR)); 3633 } else { 3634 PetscFV fv; 3635 PetscInt numComp, c; 3636 3637 PetscCall(PetscDSGetDiscretization(prob, f, (PetscObject *)&fv)); 3638 PetscCall(PetscFVGetNumComponents(fv, &numComp)); 3639 PetscCall(DMPlexPointLocalFieldRead(dm, cells[0], f, x, &xL)); 3640 PetscCall(DMPlexPointLocalFieldRead(dm, cells[1], f, x, &xR)); 3641 if (dmGrad) { 3642 PetscReal dxL[3], dxR[3]; 3643 3644 PetscCall(DMPlexPointLocalRead(dmGrad, cells[0], lgrad, &gL)); 3645 PetscCall(DMPlexPointLocalRead(dmGrad, cells[1], lgrad, &gR)); 3646 DMPlex_WaxpyD_Internal(dim, -1, cgL->centroid, fg->centroid, dxL); 3647 DMPlex_WaxpyD_Internal(dim, -1, cgR->centroid, fg->centroid, dxR); 3648 for (c = 0; c < numComp; ++c) { 3649 uLl[iface * Nc + off + c] = xL[c] + DMPlex_DotD_Internal(dim, &gL[c * dim], dxL); 3650 uRl[iface * Nc + off + c] = xR[c] + DMPlex_DotD_Internal(dim, &gR[c * dim], dxR); 3651 } 3652 } else { 3653 for (c = 0; c < numComp; ++c) { 3654 uLl[iface * Nc + off + c] = xL[c]; 3655 uRl[iface * Nc + off + c] = xR[c]; 3656 } 3657 } 3658 } 3659 } 3660 ++iface; 3661 } 3662 *Nface = iface; 3663 PetscCall(VecRestoreArrayRead(locX, &x)); 3664 PetscCall(VecRestoreArrayRead(faceGeometry, &facegeom)); 3665 PetscCall(VecRestoreArrayRead(cellGeometry, &cellgeom)); 3666 if (locGrad) PetscCall(VecRestoreArrayRead(locGrad, &lgrad)); 3667 PetscCall(PetscFree(isFE)); 3668 PetscFunctionReturn(PETSC_SUCCESS); 3669 } 3670 3671 /*@C 3672 DMPlexRestoreFaceFields - Restore the field values values for a chunk of faces 3673 3674 Input Parameters: 3675 + dm - The `DM` 3676 . fStart - The first face to include 3677 . fEnd - The first face to exclude 3678 . locX - A local vector with the solution fields 3679 . locX_t - A local vector with solution field time derivatives, or NULL 3680 . faceGeometry - A local vector with face geometry 3681 . cellGeometry - A local vector with cell geometry 3682 - locaGrad - A local vector with field gradients, or NULL 3683 3684 Output Parameters: 3685 + Nface - The number of faces with field values 3686 . uL - The field values at the left side of the face 3687 - uR - The field values at the right side of the face 3688 3689 Level: developer 3690 3691 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetFaceFields()` 3692 @*/ 3693 PetscErrorCode DMPlexRestoreFaceFields(DM dm, PetscInt fStart, PetscInt fEnd, Vec locX, Vec locX_t, Vec faceGeometry, Vec cellGeometry, Vec locGrad, PetscInt *Nface, PetscScalar **uL, PetscScalar **uR) 3694 { 3695 PetscFunctionBegin; 3696 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, uL)); 3697 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, uR)); 3698 PetscFunctionReturn(PETSC_SUCCESS); 3699 } 3700 3701 /*@C 3702 DMPlexGetFaceGeometry - Retrieve the geometric values for a chunk of faces 3703 3704 Input Parameters: 3705 + dm - The `DM` 3706 . fStart - The first face to include 3707 . fEnd - The first face to exclude 3708 . faceGeometry - A local vector with face geometry 3709 - cellGeometry - A local vector with cell geometry 3710 3711 Output Parameters: 3712 + Nface - The number of faces with field values 3713 . fgeom - The extract the face centroid and normal 3714 - vol - The cell volume 3715 3716 Level: developer 3717 3718 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetCellFields()` 3719 @*/ 3720 PetscErrorCode DMPlexGetFaceGeometry(DM dm, PetscInt fStart, PetscInt fEnd, Vec faceGeometry, Vec cellGeometry, PetscInt *Nface, PetscFVFaceGeom **fgeom, PetscReal **vol) 3721 { 3722 DM dmFace, dmCell; 3723 DMLabel ghostLabel; 3724 const PetscScalar *facegeom, *cellgeom; 3725 PetscInt dim, numFaces = fEnd - fStart, iface, face; 3726 3727 PetscFunctionBegin; 3728 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3729 PetscValidHeaderSpecific(faceGeometry, VEC_CLASSID, 4); 3730 PetscValidHeaderSpecific(cellGeometry, VEC_CLASSID, 5); 3731 PetscValidPointer(fgeom, 7); 3732 PetscValidPointer(vol, 8); 3733 PetscCall(DMGetDimension(dm, &dim)); 3734 PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 3735 PetscCall(VecGetDM(faceGeometry, &dmFace)); 3736 PetscCall(VecGetArrayRead(faceGeometry, &facegeom)); 3737 PetscCall(VecGetDM(cellGeometry, &dmCell)); 3738 PetscCall(VecGetArrayRead(cellGeometry, &cellgeom)); 3739 PetscCall(PetscMalloc1(numFaces, fgeom)); 3740 PetscCall(DMGetWorkArray(dm, numFaces * 2, MPIU_SCALAR, vol)); 3741 for (face = fStart, iface = 0; face < fEnd; ++face) { 3742 const PetscInt *cells; 3743 PetscFVFaceGeom *fg; 3744 PetscFVCellGeom *cgL, *cgR; 3745 PetscFVFaceGeom *fgeoml = *fgeom; 3746 PetscReal *voll = *vol; 3747 PetscInt ghost, d, nchild, nsupp; 3748 3749 PetscCall(DMLabelGetValue(ghostLabel, face, &ghost)); 3750 PetscCall(DMPlexGetSupportSize(dm, face, &nsupp)); 3751 PetscCall(DMPlexGetTreeChildren(dm, face, &nchild, NULL)); 3752 if (ghost >= 0 || nsupp > 2 || nchild > 0) continue; 3753 PetscCall(DMPlexPointLocalRead(dmFace, face, facegeom, &fg)); 3754 PetscCall(DMPlexGetSupport(dm, face, &cells)); 3755 PetscCall(DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cgL)); 3756 PetscCall(DMPlexPointLocalRead(dmCell, cells[1], cellgeom, &cgR)); 3757 for (d = 0; d < dim; ++d) { 3758 fgeoml[iface].centroid[d] = fg->centroid[d]; 3759 fgeoml[iface].normal[d] = fg->normal[d]; 3760 } 3761 voll[iface * 2 + 0] = cgL->volume; 3762 voll[iface * 2 + 1] = cgR->volume; 3763 ++iface; 3764 } 3765 *Nface = iface; 3766 PetscCall(VecRestoreArrayRead(faceGeometry, &facegeom)); 3767 PetscCall(VecRestoreArrayRead(cellGeometry, &cellgeom)); 3768 PetscFunctionReturn(PETSC_SUCCESS); 3769 } 3770 3771 /*@C 3772 DMPlexRestoreFaceGeometry - Restore the field values values for a chunk of faces 3773 3774 Input Parameters: 3775 + dm - The `DM` 3776 . fStart - The first face to include 3777 . fEnd - The first face to exclude 3778 . faceGeometry - A local vector with face geometry 3779 - cellGeometry - A local vector with cell geometry 3780 3781 Output Parameters: 3782 + Nface - The number of faces with field values 3783 . fgeom - The extract the face centroid and normal 3784 - vol - The cell volume 3785 3786 Level: developer 3787 3788 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetFaceFields()` 3789 @*/ 3790 PetscErrorCode DMPlexRestoreFaceGeometry(DM dm, PetscInt fStart, PetscInt fEnd, Vec faceGeometry, Vec cellGeometry, PetscInt *Nface, PetscFVFaceGeom **fgeom, PetscReal **vol) 3791 { 3792 PetscFunctionBegin; 3793 PetscCall(PetscFree(*fgeom)); 3794 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_REAL, vol)); 3795 PetscFunctionReturn(PETSC_SUCCESS); 3796 } 3797 3798 PetscErrorCode DMSNESGetFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom) 3799 { 3800 char composeStr[33] = {0}; 3801 PetscObjectId id; 3802 PetscContainer container; 3803 3804 PetscFunctionBegin; 3805 PetscCall(PetscObjectGetId((PetscObject)quad, &id)); 3806 PetscCall(PetscSNPrintf(composeStr, 32, "DMSNESGetFEGeom_%" PetscInt64_FMT "\n", id)); 3807 PetscCall(PetscObjectQuery((PetscObject)pointIS, composeStr, (PetscObject *)&container)); 3808 if (container) { 3809 PetscCall(PetscContainerGetPointer(container, (void **)geom)); 3810 } else { 3811 PetscCall(DMFieldCreateFEGeom(coordField, pointIS, quad, faceData, geom)); 3812 PetscCall(PetscContainerCreate(PETSC_COMM_SELF, &container)); 3813 PetscCall(PetscContainerSetPointer(container, (void *)*geom)); 3814 PetscCall(PetscContainerSetUserDestroy(container, PetscContainerUserDestroy_PetscFEGeom)); 3815 PetscCall(PetscObjectCompose((PetscObject)pointIS, composeStr, (PetscObject)container)); 3816 PetscCall(PetscContainerDestroy(&container)); 3817 } 3818 PetscFunctionReturn(PETSC_SUCCESS); 3819 } 3820 3821 PetscErrorCode DMSNESRestoreFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom) 3822 { 3823 PetscFunctionBegin; 3824 *geom = NULL; 3825 PetscFunctionReturn(PETSC_SUCCESS); 3826 } 3827 3828 PetscErrorCode DMPlexComputeResidual_Patch_Internal(DM dm, PetscSection section, IS cellIS, PetscReal t, Vec locX, Vec locX_t, Vec locF, void *user) 3829 { 3830 DM_Plex *mesh = (DM_Plex *)dm->data; 3831 const char *name = "Residual"; 3832 DM dmAux = NULL; 3833 DMLabel ghostLabel = NULL; 3834 PetscDS prob = NULL; 3835 PetscDS probAux = NULL; 3836 PetscBool useFEM = PETSC_FALSE; 3837 PetscBool isImplicit = (locX_t || t == PETSC_MIN_REAL) ? PETSC_TRUE : PETSC_FALSE; 3838 DMField coordField = NULL; 3839 Vec locA; 3840 PetscScalar *u = NULL, *u_t, *a, *uL = NULL, *uR = NULL; 3841 IS chunkIS; 3842 const PetscInt *cells; 3843 PetscInt cStart, cEnd, numCells; 3844 PetscInt Nf, f, totDim, totDimAux, numChunks, cellChunkSize, chunk, fStart, fEnd; 3845 PetscInt maxDegree = PETSC_MAX_INT; 3846 PetscFormKey key; 3847 PetscQuadrature affineQuad = NULL, *quads = NULL; 3848 PetscFEGeom *affineGeom = NULL, **geoms = NULL; 3849 3850 PetscFunctionBegin; 3851 PetscCall(PetscLogEventBegin(DMPLEX_ResidualFEM, dm, 0, 0, 0)); 3852 /* FEM+FVM */ 3853 /* 1: Get sizes from dm and dmAux */ 3854 PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 3855 PetscCall(DMGetDS(dm, &prob)); 3856 PetscCall(PetscDSGetNumFields(prob, &Nf)); 3857 PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 3858 PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &locA)); 3859 if (locA) { 3860 PetscCall(VecGetDM(locA, &dmAux)); 3861 PetscCall(DMGetDS(dmAux, &probAux)); 3862 PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 3863 } 3864 /* 2: Get geometric data */ 3865 for (f = 0; f < Nf; ++f) { 3866 PetscObject obj; 3867 PetscClassId id; 3868 PetscBool fimp; 3869 3870 PetscCall(PetscDSGetImplicit(prob, f, &fimp)); 3871 if (isImplicit != fimp) continue; 3872 PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 3873 PetscCall(PetscObjectGetClassId(obj, &id)); 3874 if (id == PETSCFE_CLASSID) useFEM = PETSC_TRUE; 3875 PetscCheck(id != PETSCFV_CLASSID, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Use of FVM with PCPATCH not yet implemented"); 3876 } 3877 if (useFEM) { 3878 PetscCall(DMGetCoordinateField(dm, &coordField)); 3879 PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 3880 if (maxDegree <= 1) { 3881 PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &affineQuad)); 3882 if (affineQuad) PetscCall(DMSNESGetFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom)); 3883 } else { 3884 PetscCall(PetscCalloc2(Nf, &quads, Nf, &geoms)); 3885 for (f = 0; f < Nf; ++f) { 3886 PetscObject obj; 3887 PetscClassId id; 3888 PetscBool fimp; 3889 3890 PetscCall(PetscDSGetImplicit(prob, f, &fimp)); 3891 if (isImplicit != fimp) continue; 3892 PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 3893 PetscCall(PetscObjectGetClassId(obj, &id)); 3894 if (id == PETSCFE_CLASSID) { 3895 PetscFE fe = (PetscFE)obj; 3896 3897 PetscCall(PetscFEGetQuadrature(fe, &quads[f])); 3898 PetscCall(PetscObjectReference((PetscObject)quads[f])); 3899 PetscCall(DMSNESGetFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f])); 3900 } 3901 } 3902 } 3903 } 3904 /* Loop over chunks */ 3905 PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 3906 PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 3907 if (useFEM) PetscCall(ISCreate(PETSC_COMM_SELF, &chunkIS)); 3908 numCells = cEnd - cStart; 3909 numChunks = 1; 3910 cellChunkSize = numCells / numChunks; 3911 numChunks = PetscMin(1, numCells); 3912 key.label = NULL; 3913 key.value = 0; 3914 key.part = 0; 3915 for (chunk = 0; chunk < numChunks; ++chunk) { 3916 PetscScalar *elemVec, *fluxL = NULL, *fluxR = NULL; 3917 PetscReal *vol = NULL; 3918 PetscFVFaceGeom *fgeom = NULL; 3919 PetscInt cS = cStart + chunk * cellChunkSize, cE = PetscMin(cS + cellChunkSize, cEnd), numCells = cE - cS, c; 3920 PetscInt numFaces = 0; 3921 3922 /* Extract field coefficients */ 3923 if (useFEM) { 3924 PetscCall(ISGetPointSubrange(chunkIS, cS, cE, cells)); 3925 PetscCall(DMPlexGetCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a)); 3926 PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec)); 3927 PetscCall(PetscArrayzero(elemVec, numCells * totDim)); 3928 } 3929 /* TODO We will interlace both our field coefficients (u, u_t, uL, uR, etc.) and our output (elemVec, fL, fR). I think this works */ 3930 /* Loop over fields */ 3931 for (f = 0; f < Nf; ++f) { 3932 PetscObject obj; 3933 PetscClassId id; 3934 PetscBool fimp; 3935 PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset; 3936 3937 key.field = f; 3938 PetscCall(PetscDSGetImplicit(prob, f, &fimp)); 3939 if (isImplicit != fimp) continue; 3940 PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 3941 PetscCall(PetscObjectGetClassId(obj, &id)); 3942 if (id == PETSCFE_CLASSID) { 3943 PetscFE fe = (PetscFE)obj; 3944 PetscFEGeom *geom = affineGeom ? affineGeom : geoms[f]; 3945 PetscFEGeom *chunkGeom = NULL; 3946 PetscQuadrature quad = affineQuad ? affineQuad : quads[f]; 3947 PetscInt Nq, Nb; 3948 3949 PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 3950 PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL)); 3951 PetscCall(PetscFEGetDimension(fe, &Nb)); 3952 blockSize = Nb; 3953 batchSize = numBlocks * blockSize; 3954 PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 3955 numChunks = numCells / (numBatches * batchSize); 3956 Ne = numChunks * numBatches * batchSize; 3957 Nr = numCells % (numBatches * batchSize); 3958 offset = numCells - Nr; 3959 /* Integrate FE residual to get elemVec (need fields at quadrature points) */ 3960 /* For FV, I think we use a P0 basis and the cell coefficients (for subdivided cells, we can tweak the basis tabulation to be the indicator function) */ 3961 PetscCall(PetscFEGeomGetChunk(geom, 0, offset, &chunkGeom)); 3962 PetscCall(PetscFEIntegrateResidual(prob, key, Ne, chunkGeom, u, u_t, probAux, a, t, elemVec)); 3963 PetscCall(PetscFEGeomGetChunk(geom, offset, numCells, &chunkGeom)); 3964 PetscCall(PetscFEIntegrateResidual(prob, key, Nr, chunkGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, probAux, &a[offset * totDimAux], t, &elemVec[offset * totDim])); 3965 PetscCall(PetscFEGeomRestoreChunk(geom, offset, numCells, &chunkGeom)); 3966 } else if (id == PETSCFV_CLASSID) { 3967 PetscFV fv = (PetscFV)obj; 3968 3969 Ne = numFaces; 3970 /* Riemann solve over faces (need fields at face centroids) */ 3971 /* We need to evaluate FE fields at those coordinates */ 3972 PetscCall(PetscFVIntegrateRHSFunction(fv, prob, f, Ne, fgeom, vol, uL, uR, fluxL, fluxR)); 3973 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f); 3974 } 3975 /* Loop over domain */ 3976 if (useFEM) { 3977 /* Add elemVec to locX */ 3978 for (c = cS; c < cE; ++c) { 3979 const PetscInt cell = cells ? cells[c] : c; 3980 const PetscInt cind = c - cStart; 3981 3982 if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, name, totDim, &elemVec[cind * totDim])); 3983 if (ghostLabel) { 3984 PetscInt ghostVal; 3985 3986 PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal)); 3987 if (ghostVal > 0) continue; 3988 } 3989 PetscCall(DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind * totDim], ADD_ALL_VALUES)); 3990 } 3991 } 3992 /* Handle time derivative */ 3993 if (locX_t) { 3994 PetscScalar *x_t, *fa; 3995 3996 PetscCall(VecGetArray(locF, &fa)); 3997 PetscCall(VecGetArray(locX_t, &x_t)); 3998 for (f = 0; f < Nf; ++f) { 3999 PetscFV fv; 4000 PetscObject obj; 4001 PetscClassId id; 4002 PetscInt pdim, d; 4003 4004 PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 4005 PetscCall(PetscObjectGetClassId(obj, &id)); 4006 if (id != PETSCFV_CLASSID) continue; 4007 fv = (PetscFV)obj; 4008 PetscCall(PetscFVGetNumComponents(fv, &pdim)); 4009 for (c = cS; c < cE; ++c) { 4010 const PetscInt cell = cells ? cells[c] : c; 4011 PetscScalar *u_t, *r; 4012 4013 if (ghostLabel) { 4014 PetscInt ghostVal; 4015 4016 PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal)); 4017 if (ghostVal > 0) continue; 4018 } 4019 PetscCall(DMPlexPointLocalFieldRead(dm, cell, f, x_t, &u_t)); 4020 PetscCall(DMPlexPointLocalFieldRef(dm, cell, f, fa, &r)); 4021 for (d = 0; d < pdim; ++d) r[d] += u_t[d]; 4022 } 4023 } 4024 PetscCall(VecRestoreArray(locX_t, &x_t)); 4025 PetscCall(VecRestoreArray(locF, &fa)); 4026 } 4027 if (useFEM) { 4028 PetscCall(DMPlexRestoreCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a)); 4029 PetscCall(DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec)); 4030 } 4031 } 4032 if (useFEM) PetscCall(ISDestroy(&chunkIS)); 4033 PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 4034 /* TODO Could include boundary residual here (see DMPlexComputeResidual_Internal) */ 4035 if (useFEM) { 4036 if (maxDegree <= 1) { 4037 PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom)); 4038 PetscCall(PetscQuadratureDestroy(&affineQuad)); 4039 } else { 4040 for (f = 0; f < Nf; ++f) { 4041 PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f])); 4042 PetscCall(PetscQuadratureDestroy(&quads[f])); 4043 } 4044 PetscCall(PetscFree2(quads, geoms)); 4045 } 4046 } 4047 PetscCall(PetscLogEventEnd(DMPLEX_ResidualFEM, dm, 0, 0, 0)); 4048 PetscFunctionReturn(PETSC_SUCCESS); 4049 } 4050 4051 /* 4052 We always assemble JacP, and if the matrix is different from Jac and two different sets of point functions are provided, we also assemble Jac 4053 4054 X - The local solution vector 4055 X_t - The local solution time derivative vector, or NULL 4056 */ 4057 PetscErrorCode DMPlexComputeJacobian_Patch_Internal(DM dm, PetscSection section, PetscSection globalSection, IS cellIS, PetscReal t, PetscReal X_tShift, Vec X, Vec X_t, Mat Jac, Mat JacP, void *ctx) 4058 { 4059 DM_Plex *mesh = (DM_Plex *)dm->data; 4060 const char *name = "Jacobian", *nameP = "JacobianPre"; 4061 DM dmAux = NULL; 4062 PetscDS prob, probAux = NULL; 4063 PetscSection sectionAux = NULL; 4064 Vec A; 4065 DMField coordField; 4066 PetscFEGeom *cgeomFEM; 4067 PetscQuadrature qGeom = NULL; 4068 Mat J = Jac, JP = JacP; 4069 PetscScalar *work, *u = NULL, *u_t = NULL, *a = NULL, *elemMat = NULL, *elemMatP = NULL, *elemMatD = NULL; 4070 PetscBool hasJac, hasPrec, hasDyn, assembleJac, *isFE, hasFV = PETSC_FALSE; 4071 const PetscInt *cells; 4072 PetscFormKey key; 4073 PetscInt Nf, fieldI, fieldJ, maxDegree, numCells, cStart, cEnd, numChunks, chunkSize, chunk, totDim, totDimAux = 0, sz, wsz, off = 0, offCell = 0; 4074 4075 PetscFunctionBegin; 4076 PetscCall(ISGetLocalSize(cellIS, &numCells)); 4077 PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 4078 PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 4079 PetscCall(DMGetDS(dm, &prob)); 4080 PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &A)); 4081 if (A) { 4082 PetscCall(VecGetDM(A, &dmAux)); 4083 PetscCall(DMGetLocalSection(dmAux, §ionAux)); 4084 PetscCall(DMGetDS(dmAux, &probAux)); 4085 } 4086 /* Get flags */ 4087 PetscCall(PetscDSGetNumFields(prob, &Nf)); 4088 PetscCall(DMGetWorkArray(dm, Nf, MPIU_BOOL, &isFE)); 4089 for (fieldI = 0; fieldI < Nf; ++fieldI) { 4090 PetscObject disc; 4091 PetscClassId id; 4092 PetscCall(PetscDSGetDiscretization(prob, fieldI, &disc)); 4093 PetscCall(PetscObjectGetClassId(disc, &id)); 4094 if (id == PETSCFE_CLASSID) { 4095 isFE[fieldI] = PETSC_TRUE; 4096 } else if (id == PETSCFV_CLASSID) { 4097 hasFV = PETSC_TRUE; 4098 isFE[fieldI] = PETSC_FALSE; 4099 } 4100 } 4101 PetscCall(PetscDSHasJacobian(prob, &hasJac)); 4102 PetscCall(PetscDSHasJacobianPreconditioner(prob, &hasPrec)); 4103 PetscCall(PetscDSHasDynamicJacobian(prob, &hasDyn)); 4104 assembleJac = hasJac && hasPrec && (Jac != JacP) ? PETSC_TRUE : PETSC_FALSE; 4105 hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE; 4106 if (hasFV) PetscCall(MatSetOption(JP, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE)); /* No allocated space for FV stuff, so ignore the zero entries */ 4107 PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 4108 if (probAux) PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 4109 /* Compute batch sizes */ 4110 if (isFE[0]) { 4111 PetscFE fe; 4112 PetscQuadrature q; 4113 PetscInt numQuadPoints, numBatches, batchSize, numBlocks, blockSize, Nb; 4114 4115 PetscCall(PetscDSGetDiscretization(prob, 0, (PetscObject *)&fe)); 4116 PetscCall(PetscFEGetQuadrature(fe, &q)); 4117 PetscCall(PetscQuadratureGetData(q, NULL, NULL, &numQuadPoints, NULL, NULL)); 4118 PetscCall(PetscFEGetDimension(fe, &Nb)); 4119 PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 4120 blockSize = Nb * numQuadPoints; 4121 batchSize = numBlocks * blockSize; 4122 chunkSize = numBatches * batchSize; 4123 numChunks = numCells / chunkSize + numCells % chunkSize; 4124 PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 4125 } else { 4126 chunkSize = numCells; 4127 numChunks = 1; 4128 } 4129 /* Get work space */ 4130 wsz = (((X ? 1 : 0) + (X_t ? 1 : 0) + (dmAux ? 1 : 0)) * totDim + ((hasJac ? 1 : 0) + (hasPrec ? 1 : 0) + (hasDyn ? 1 : 0)) * totDim * totDim) * chunkSize; 4131 PetscCall(DMGetWorkArray(dm, wsz, MPIU_SCALAR, &work)); 4132 PetscCall(PetscArrayzero(work, wsz)); 4133 off = 0; 4134 u = X ? (sz = chunkSize * totDim, off += sz, work + off - sz) : NULL; 4135 u_t = X_t ? (sz = chunkSize * totDim, off += sz, work + off - sz) : NULL; 4136 a = dmAux ? (sz = chunkSize * totDimAux, off += sz, work + off - sz) : NULL; 4137 elemMat = hasJac ? (sz = chunkSize * totDim * totDim, off += sz, work + off - sz) : NULL; 4138 elemMatP = hasPrec ? (sz = chunkSize * totDim * totDim, off += sz, work + off - sz) : NULL; 4139 elemMatD = hasDyn ? (sz = chunkSize * totDim * totDim, off += sz, work + off - sz) : NULL; 4140 PetscCheck(off == wsz, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Error is workspace size %" PetscInt_FMT " should be %" PetscInt_FMT, off, wsz); 4141 /* Setup geometry */ 4142 PetscCall(DMGetCoordinateField(dm, &coordField)); 4143 PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 4144 if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &qGeom)); 4145 if (!qGeom) { 4146 PetscFE fe; 4147 4148 PetscCall(PetscDSGetDiscretization(prob, 0, (PetscObject *)&fe)); 4149 PetscCall(PetscFEGetQuadrature(fe, &qGeom)); 4150 PetscCall(PetscObjectReference((PetscObject)qGeom)); 4151 } 4152 PetscCall(DMSNESGetFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 4153 /* Compute volume integrals */ 4154 if (assembleJac) PetscCall(MatZeroEntries(J)); 4155 PetscCall(MatZeroEntries(JP)); 4156 key.label = NULL; 4157 key.value = 0; 4158 key.part = 0; 4159 for (chunk = 0; chunk < numChunks; ++chunk, offCell += chunkSize) { 4160 const PetscInt Ncell = PetscMin(chunkSize, numCells - offCell); 4161 PetscInt c; 4162 4163 /* Extract values */ 4164 for (c = 0; c < Ncell; ++c) { 4165 const PetscInt cell = cells ? cells[c + offCell] : c + offCell; 4166 PetscScalar *x = NULL, *x_t = NULL; 4167 PetscInt i; 4168 4169 if (X) { 4170 PetscCall(DMPlexVecGetClosure(dm, section, X, cell, NULL, &x)); 4171 for (i = 0; i < totDim; ++i) u[c * totDim + i] = x[i]; 4172 PetscCall(DMPlexVecRestoreClosure(dm, section, X, cell, NULL, &x)); 4173 } 4174 if (X_t) { 4175 PetscCall(DMPlexVecGetClosure(dm, section, X_t, cell, NULL, &x_t)); 4176 for (i = 0; i < totDim; ++i) u_t[c * totDim + i] = x_t[i]; 4177 PetscCall(DMPlexVecRestoreClosure(dm, section, X_t, cell, NULL, &x_t)); 4178 } 4179 if (dmAux) { 4180 PetscCall(DMPlexVecGetClosure(dmAux, sectionAux, A, cell, NULL, &x)); 4181 for (i = 0; i < totDimAux; ++i) a[c * totDimAux + i] = x[i]; 4182 PetscCall(DMPlexVecRestoreClosure(dmAux, sectionAux, A, cell, NULL, &x)); 4183 } 4184 } 4185 for (fieldI = 0; fieldI < Nf; ++fieldI) { 4186 PetscFE fe; 4187 PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe)); 4188 for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 4189 key.field = fieldI * Nf + fieldJ; 4190 if (hasJac) PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMat)); 4191 if (hasPrec) PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, key, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMatP)); 4192 if (hasDyn) PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMatD)); 4193 } 4194 /* For finite volume, add the identity */ 4195 if (!isFE[fieldI]) { 4196 PetscFV fv; 4197 PetscInt eOffset = 0, Nc, fc, foff; 4198 4199 PetscCall(PetscDSGetFieldOffset(prob, fieldI, &foff)); 4200 PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fv)); 4201 PetscCall(PetscFVGetNumComponents(fv, &Nc)); 4202 for (c = 0; c < chunkSize; ++c, eOffset += totDim * totDim) { 4203 for (fc = 0; fc < Nc; ++fc) { 4204 const PetscInt i = foff + fc; 4205 if (hasJac) elemMat[eOffset + i * totDim + i] = 1.0; 4206 if (hasPrec) elemMatP[eOffset + i * totDim + i] = 1.0; 4207 } 4208 } 4209 } 4210 } 4211 /* Add contribution from X_t */ 4212 if (hasDyn) { 4213 for (c = 0; c < chunkSize * totDim * totDim; ++c) elemMat[c] += X_tShift * elemMatD[c]; 4214 } 4215 /* Insert values into matrix */ 4216 for (c = 0; c < Ncell; ++c) { 4217 const PetscInt cell = cells ? cells[c + offCell] : c + offCell; 4218 if (mesh->printFEM > 1) { 4219 if (hasJac) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[(c - cStart) * totDim * totDim])); 4220 if (hasPrec) PetscCall(DMPrintCellMatrix(cell, nameP, totDim, totDim, &elemMatP[(c - cStart) * totDim * totDim])); 4221 } 4222 if (assembleJac) PetscCall(DMPlexMatSetClosure(dm, section, globalSection, Jac, cell, &elemMat[(c - cStart) * totDim * totDim], ADD_VALUES)); 4223 PetscCall(DMPlexMatSetClosure(dm, section, globalSection, JP, cell, &elemMat[(c - cStart) * totDim * totDim], ADD_VALUES)); 4224 } 4225 } 4226 /* Cleanup */ 4227 PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 4228 PetscCall(PetscQuadratureDestroy(&qGeom)); 4229 if (hasFV) PetscCall(MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_FALSE)); 4230 PetscCall(DMRestoreWorkArray(dm, Nf, MPIU_BOOL, &isFE)); 4231 PetscCall(DMRestoreWorkArray(dm, ((1 + (X_t ? 1 : 0) + (dmAux ? 1 : 0)) * totDim + ((hasJac ? 1 : 0) + (hasPrec ? 1 : 0) + (hasDyn ? 1 : 0)) * totDim * totDim) * chunkSize, MPIU_SCALAR, &work)); 4232 /* Compute boundary integrals */ 4233 /* PetscCall(DMPlexComputeBdJacobian_Internal(dm, X, X_t, t, X_tShift, Jac, JacP, ctx)); */ 4234 /* Assemble matrix */ 4235 if (assembleJac) { 4236 PetscCall(MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY)); 4237 PetscCall(MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY)); 4238 } 4239 PetscCall(MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY)); 4240 PetscCall(MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY)); 4241 PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 4242 PetscFunctionReturn(PETSC_SUCCESS); 4243 } 4244 4245 /******** FEM Assembly Function ********/ 4246 4247 static PetscErrorCode DMConvertPlex_Internal(DM dm, DM *plex, PetscBool copy) 4248 { 4249 PetscBool isPlex; 4250 4251 PetscFunctionBegin; 4252 PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMPLEX, &isPlex)); 4253 if (isPlex) { 4254 *plex = dm; 4255 PetscCall(PetscObjectReference((PetscObject)dm)); 4256 } else { 4257 PetscCall(PetscObjectQuery((PetscObject)dm, "dm_plex", (PetscObject *)plex)); 4258 if (!*plex) { 4259 PetscCall(DMConvert(dm, DMPLEX, plex)); 4260 PetscCall(PetscObjectCompose((PetscObject)dm, "dm_plex", (PetscObject)*plex)); 4261 if (copy) PetscCall(DMCopyAuxiliaryVec(dm, *plex)); 4262 } else { 4263 PetscCall(PetscObjectReference((PetscObject)*plex)); 4264 } 4265 } 4266 PetscFunctionReturn(PETSC_SUCCESS); 4267 } 4268 4269 /*@ 4270 DMPlexGetGeometryFVM - Return precomputed geometric data 4271 4272 Collective on dm 4273 4274 Input Parameter: 4275 . dm - The `DM` 4276 4277 Output Parameters: 4278 + facegeom - The values precomputed from face geometry 4279 . cellgeom - The values precomputed from cell geometry 4280 - minRadius - The minimum radius over the mesh of an inscribed sphere in a cell 4281 4282 Level: developer 4283 4284 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMTSSetRHSFunctionLocal()` 4285 @*/ 4286 PetscErrorCode DMPlexGetGeometryFVM(DM dm, Vec *facegeom, Vec *cellgeom, PetscReal *minRadius) 4287 { 4288 DM plex; 4289 4290 PetscFunctionBegin; 4291 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4292 PetscCall(DMConvertPlex_Internal(dm, &plex, PETSC_TRUE)); 4293 PetscCall(DMPlexGetDataFVM(plex, NULL, cellgeom, facegeom, NULL)); 4294 if (minRadius) PetscCall(DMPlexGetMinRadius(plex, minRadius)); 4295 PetscCall(DMDestroy(&plex)); 4296 PetscFunctionReturn(PETSC_SUCCESS); 4297 } 4298 4299 /*@ 4300 DMPlexGetGradientDM - Return gradient data layout 4301 4302 Collective on dm 4303 4304 Input Parameters: 4305 + dm - The `DM` 4306 - fv - The PetscFV 4307 4308 Output Parameter: 4309 . dmGrad - The layout for gradient values 4310 4311 Level: developer 4312 4313 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `DMPlexGetGeometryFVM()` 4314 @*/ 4315 PetscErrorCode DMPlexGetGradientDM(DM dm, PetscFV fv, DM *dmGrad) 4316 { 4317 DM plex; 4318 PetscBool computeGradients; 4319 4320 PetscFunctionBegin; 4321 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4322 PetscValidHeaderSpecific(fv, PETSCFV_CLASSID, 2); 4323 PetscValidPointer(dmGrad, 3); 4324 PetscCall(PetscFVGetComputeGradients(fv, &computeGradients)); 4325 if (!computeGradients) { 4326 *dmGrad = NULL; 4327 PetscFunctionReturn(PETSC_SUCCESS); 4328 } 4329 PetscCall(DMConvertPlex_Internal(dm, &plex, PETSC_TRUE)); 4330 PetscCall(DMPlexGetDataFVM(plex, fv, NULL, NULL, dmGrad)); 4331 PetscCall(DMDestroy(&plex)); 4332 PetscFunctionReturn(PETSC_SUCCESS); 4333 } 4334 4335 static PetscErrorCode DMPlexComputeBdResidual_Single_Internal(DM dm, PetscReal t, PetscWeakForm wf, PetscFormKey key, Vec locX, Vec locX_t, Vec locF, DMField coordField, IS facetIS) 4336 { 4337 DM_Plex *mesh = (DM_Plex *)dm->data; 4338 DM plex = NULL, plexA = NULL; 4339 DMEnclosureType encAux; 4340 PetscDS prob, probAux = NULL; 4341 PetscSection section, sectionAux = NULL; 4342 Vec locA = NULL; 4343 PetscScalar *u = NULL, *u_t = NULL, *a = NULL, *elemVec = NULL; 4344 PetscInt totDim, totDimAux = 0; 4345 4346 PetscFunctionBegin; 4347 PetscCall(DMConvert(dm, DMPLEX, &plex)); 4348 PetscCall(DMGetLocalSection(dm, §ion)); 4349 PetscCall(DMGetDS(dm, &prob)); 4350 PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 4351 PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &locA)); 4352 if (locA) { 4353 DM dmAux; 4354 4355 PetscCall(VecGetDM(locA, &dmAux)); 4356 PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 4357 PetscCall(DMConvert(dmAux, DMPLEX, &plexA)); 4358 PetscCall(DMGetDS(plexA, &probAux)); 4359 PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 4360 PetscCall(DMGetLocalSection(plexA, §ionAux)); 4361 } 4362 { 4363 PetscFEGeom *fgeom; 4364 PetscInt maxDegree; 4365 PetscQuadrature qGeom = NULL; 4366 IS pointIS; 4367 const PetscInt *points; 4368 PetscInt numFaces, face, Nq; 4369 4370 PetscCall(DMLabelGetStratumIS(key.label, key.value, &pointIS)); 4371 if (!pointIS) goto end; /* No points with that id on this process */ 4372 { 4373 IS isectIS; 4374 4375 /* TODO: Special cases of ISIntersect where it is quick to check a priori if one is a superset of the other */ 4376 PetscCall(ISIntersect_Caching_Internal(facetIS, pointIS, &isectIS)); 4377 PetscCall(ISDestroy(&pointIS)); 4378 pointIS = isectIS; 4379 } 4380 PetscCall(ISGetLocalSize(pointIS, &numFaces)); 4381 PetscCall(ISGetIndices(pointIS, &points)); 4382 PetscCall(PetscMalloc4(numFaces * totDim, &u, locX_t ? numFaces * totDim : 0, &u_t, numFaces * totDim, &elemVec, locA ? numFaces * totDimAux : 0, &a)); 4383 PetscCall(DMFieldGetDegree(coordField, pointIS, NULL, &maxDegree)); 4384 if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, pointIS, &qGeom)); 4385 if (!qGeom) { 4386 PetscFE fe; 4387 4388 PetscCall(PetscDSGetDiscretization(prob, key.field, (PetscObject *)&fe)); 4389 PetscCall(PetscFEGetFaceQuadrature(fe, &qGeom)); 4390 PetscCall(PetscObjectReference((PetscObject)qGeom)); 4391 } 4392 PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL)); 4393 PetscCall(DMSNESGetFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 4394 for (face = 0; face < numFaces; ++face) { 4395 const PetscInt point = points[face], *support; 4396 PetscScalar *x = NULL; 4397 PetscInt i; 4398 4399 PetscCall(DMPlexGetSupport(dm, point, &support)); 4400 PetscCall(DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x)); 4401 for (i = 0; i < totDim; ++i) u[face * totDim + i] = x[i]; 4402 PetscCall(DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x)); 4403 if (locX_t) { 4404 PetscCall(DMPlexVecGetClosure(plex, section, locX_t, support[0], NULL, &x)); 4405 for (i = 0; i < totDim; ++i) u_t[face * totDim + i] = x[i]; 4406 PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, support[0], NULL, &x)); 4407 } 4408 if (locA) { 4409 PetscInt subp; 4410 4411 PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp)); 4412 PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x)); 4413 for (i = 0; i < totDimAux; ++i) a[face * totDimAux + i] = x[i]; 4414 PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x)); 4415 } 4416 } 4417 PetscCall(PetscArrayzero(elemVec, numFaces * totDim)); 4418 { 4419 PetscFE fe; 4420 PetscInt Nb; 4421 PetscFEGeom *chunkGeom = NULL; 4422 /* Conforming batches */ 4423 PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize; 4424 /* Remainder */ 4425 PetscInt Nr, offset; 4426 4427 PetscCall(PetscDSGetDiscretization(prob, key.field, (PetscObject *)&fe)); 4428 PetscCall(PetscFEGetDimension(fe, &Nb)); 4429 PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 4430 /* TODO: documentation is unclear about what is going on with these numbers: how should Nb / Nq factor in ? */ 4431 blockSize = Nb; 4432 batchSize = numBlocks * blockSize; 4433 PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 4434 numChunks = numFaces / (numBatches * batchSize); 4435 Ne = numChunks * numBatches * batchSize; 4436 Nr = numFaces % (numBatches * batchSize); 4437 offset = numFaces - Nr; 4438 PetscCall(PetscFEGeomGetChunk(fgeom, 0, offset, &chunkGeom)); 4439 PetscCall(PetscFEIntegrateBdResidual(prob, wf, key, Ne, chunkGeom, u, u_t, probAux, a, t, elemVec)); 4440 PetscCall(PetscFEGeomRestoreChunk(fgeom, 0, offset, &chunkGeom)); 4441 PetscCall(PetscFEGeomGetChunk(fgeom, offset, numFaces, &chunkGeom)); 4442 PetscCall(PetscFEIntegrateBdResidual(prob, wf, key, Nr, chunkGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, probAux, a ? &a[offset * totDimAux] : NULL, t, &elemVec[offset * totDim])); 4443 PetscCall(PetscFEGeomRestoreChunk(fgeom, offset, numFaces, &chunkGeom)); 4444 } 4445 for (face = 0; face < numFaces; ++face) { 4446 const PetscInt point = points[face], *support; 4447 4448 if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(point, "BdResidual", totDim, &elemVec[face * totDim])); 4449 PetscCall(DMPlexGetSupport(plex, point, &support)); 4450 PetscCall(DMPlexVecSetClosure(plex, NULL, locF, support[0], &elemVec[face * totDim], ADD_ALL_VALUES)); 4451 } 4452 PetscCall(DMSNESRestoreFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 4453 PetscCall(PetscQuadratureDestroy(&qGeom)); 4454 PetscCall(ISRestoreIndices(pointIS, &points)); 4455 PetscCall(ISDestroy(&pointIS)); 4456 PetscCall(PetscFree4(u, u_t, elemVec, a)); 4457 } 4458 end: 4459 PetscCall(DMDestroy(&plex)); 4460 PetscCall(DMDestroy(&plexA)); 4461 PetscFunctionReturn(PETSC_SUCCESS); 4462 } 4463 4464 PetscErrorCode DMPlexComputeBdResidualSingle(DM dm, PetscReal t, PetscWeakForm wf, PetscFormKey key, Vec locX, Vec locX_t, Vec locF) 4465 { 4466 DMField coordField; 4467 DMLabel depthLabel; 4468 IS facetIS; 4469 PetscInt dim; 4470 4471 PetscFunctionBegin; 4472 PetscCall(DMGetDimension(dm, &dim)); 4473 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 4474 PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 4475 PetscCall(DMGetCoordinateField(dm, &coordField)); 4476 PetscCall(DMPlexComputeBdResidual_Single_Internal(dm, t, wf, key, locX, locX_t, locF, coordField, facetIS)); 4477 PetscCall(ISDestroy(&facetIS)); 4478 PetscFunctionReturn(PETSC_SUCCESS); 4479 } 4480 4481 PetscErrorCode DMPlexComputeBdResidual_Internal(DM dm, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user) 4482 { 4483 PetscDS prob; 4484 PetscInt numBd, bd; 4485 DMField coordField = NULL; 4486 IS facetIS = NULL; 4487 DMLabel depthLabel; 4488 PetscInt dim; 4489 4490 PetscFunctionBegin; 4491 PetscCall(DMGetDS(dm, &prob)); 4492 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 4493 PetscCall(DMGetDimension(dm, &dim)); 4494 PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 4495 PetscCall(PetscDSGetNumBoundary(prob, &numBd)); 4496 for (bd = 0; bd < numBd; ++bd) { 4497 PetscWeakForm wf; 4498 DMBoundaryConditionType type; 4499 DMLabel label; 4500 const PetscInt *values; 4501 PetscInt field, numValues, v; 4502 PetscObject obj; 4503 PetscClassId id; 4504 PetscFormKey key; 4505 4506 PetscCall(PetscDSGetBoundary(prob, bd, &wf, &type, NULL, &label, &numValues, &values, &field, NULL, NULL, NULL, NULL, NULL)); 4507 if (type & DM_BC_ESSENTIAL) continue; 4508 PetscCall(PetscDSGetDiscretization(prob, field, &obj)); 4509 PetscCall(PetscObjectGetClassId(obj, &id)); 4510 if (id != PETSCFE_CLASSID) continue; 4511 if (!facetIS) { 4512 DMLabel depthLabel; 4513 PetscInt dim; 4514 4515 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 4516 PetscCall(DMGetDimension(dm, &dim)); 4517 PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 4518 } 4519 PetscCall(DMGetCoordinateField(dm, &coordField)); 4520 for (v = 0; v < numValues; ++v) { 4521 key.label = label; 4522 key.value = values[v]; 4523 key.field = field; 4524 key.part = 0; 4525 PetscCall(DMPlexComputeBdResidual_Single_Internal(dm, t, wf, key, locX, locX_t, locF, coordField, facetIS)); 4526 } 4527 } 4528 PetscCall(ISDestroy(&facetIS)); 4529 PetscFunctionReturn(PETSC_SUCCESS); 4530 } 4531 4532 PetscErrorCode DMPlexComputeResidual_Internal(DM dm, PetscFormKey key, IS cellIS, PetscReal time, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user) 4533 { 4534 DM_Plex *mesh = (DM_Plex *)dm->data; 4535 const char *name = "Residual"; 4536 DM dmAux = NULL; 4537 DM dmGrad = NULL; 4538 DMLabel ghostLabel = NULL; 4539 PetscDS ds = NULL; 4540 PetscDS dsAux = NULL; 4541 PetscSection section = NULL; 4542 PetscBool useFEM = PETSC_FALSE; 4543 PetscBool useFVM = PETSC_FALSE; 4544 PetscBool isImplicit = (locX_t || time == PETSC_MIN_REAL) ? PETSC_TRUE : PETSC_FALSE; 4545 PetscFV fvm = NULL; 4546 PetscFVCellGeom *cgeomFVM = NULL; 4547 PetscFVFaceGeom *fgeomFVM = NULL; 4548 DMField coordField = NULL; 4549 Vec locA, cellGeometryFVM = NULL, faceGeometryFVM = NULL, grad, locGrad = NULL; 4550 PetscScalar *u = NULL, *u_t, *a, *uL, *uR; 4551 IS chunkIS; 4552 const PetscInt *cells; 4553 PetscInt cStart, cEnd, numCells; 4554 PetscInt Nf, f, totDim, totDimAux, numChunks, cellChunkSize, faceChunkSize, chunk, fStart, fEnd; 4555 PetscInt maxDegree = PETSC_MAX_INT; 4556 PetscQuadrature affineQuad = NULL, *quads = NULL; 4557 PetscFEGeom *affineGeom = NULL, **geoms = NULL; 4558 4559 PetscFunctionBegin; 4560 if (!cellIS) PetscFunctionReturn(PETSC_SUCCESS); 4561 PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 4562 if (cStart >= cEnd) PetscFunctionReturn(PETSC_SUCCESS); 4563 PetscCall(PetscLogEventBegin(DMPLEX_ResidualFEM, dm, 0, 0, 0)); 4564 /* TODO The places where we have to use isFE are probably the member functions for the PetscDisc class */ 4565 /* TODO The FVM geometry is over-manipulated. Make the precalc functions return exactly what we need */ 4566 /* FEM+FVM */ 4567 PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 4568 /* 1: Get sizes from dm and dmAux */ 4569 PetscCall(DMGetLocalSection(dm, §ion)); 4570 PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 4571 PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds)); 4572 PetscCall(PetscDSGetNumFields(ds, &Nf)); 4573 PetscCall(PetscDSGetTotalDimension(ds, &totDim)); 4574 PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &locA)); 4575 if (locA) { 4576 PetscInt subcell; 4577 PetscCall(VecGetDM(locA, &dmAux)); 4578 PetscCall(DMGetEnclosurePoint(dmAux, dm, DM_ENC_UNKNOWN, cells ? cells[cStart] : cStart, &subcell)); 4579 PetscCall(DMGetCellDS(dmAux, subcell, &dsAux)); 4580 PetscCall(PetscDSGetTotalDimension(dsAux, &totDimAux)); 4581 } 4582 /* 2: Get geometric data */ 4583 for (f = 0; f < Nf; ++f) { 4584 PetscObject obj; 4585 PetscClassId id; 4586 PetscBool fimp; 4587 4588 PetscCall(PetscDSGetImplicit(ds, f, &fimp)); 4589 if (isImplicit != fimp) continue; 4590 PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 4591 PetscCall(PetscObjectGetClassId(obj, &id)); 4592 if (id == PETSCFE_CLASSID) useFEM = PETSC_TRUE; 4593 if (id == PETSCFV_CLASSID) { 4594 useFVM = PETSC_TRUE; 4595 fvm = (PetscFV)obj; 4596 } 4597 } 4598 if (useFEM) { 4599 PetscCall(DMGetCoordinateField(dm, &coordField)); 4600 PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 4601 if (maxDegree <= 1) { 4602 PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &affineQuad)); 4603 if (affineQuad) PetscCall(DMSNESGetFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom)); 4604 } else { 4605 PetscCall(PetscCalloc2(Nf, &quads, Nf, &geoms)); 4606 for (f = 0; f < Nf; ++f) { 4607 PetscObject obj; 4608 PetscClassId id; 4609 PetscBool fimp; 4610 4611 PetscCall(PetscDSGetImplicit(ds, f, &fimp)); 4612 if (isImplicit != fimp) continue; 4613 PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 4614 PetscCall(PetscObjectGetClassId(obj, &id)); 4615 if (id == PETSCFE_CLASSID) { 4616 PetscFE fe = (PetscFE)obj; 4617 4618 PetscCall(PetscFEGetQuadrature(fe, &quads[f])); 4619 PetscCall(PetscObjectReference((PetscObject)quads[f])); 4620 PetscCall(DMSNESGetFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f])); 4621 } 4622 } 4623 } 4624 } 4625 if (useFVM) { 4626 PetscCall(DMPlexGetGeometryFVM(dm, &faceGeometryFVM, &cellGeometryFVM, NULL)); 4627 PetscCall(VecGetArrayRead(faceGeometryFVM, (const PetscScalar **)&fgeomFVM)); 4628 PetscCall(VecGetArrayRead(cellGeometryFVM, (const PetscScalar **)&cgeomFVM)); 4629 /* Reconstruct and limit cell gradients */ 4630 PetscCall(DMPlexGetGradientDM(dm, fvm, &dmGrad)); 4631 if (dmGrad) { 4632 PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 4633 PetscCall(DMGetGlobalVector(dmGrad, &grad)); 4634 PetscCall(DMPlexReconstructGradients_Internal(dm, fvm, fStart, fEnd, faceGeometryFVM, cellGeometryFVM, locX, grad)); 4635 /* Communicate gradient values */ 4636 PetscCall(DMGetLocalVector(dmGrad, &locGrad)); 4637 PetscCall(DMGlobalToLocalBegin(dmGrad, grad, INSERT_VALUES, locGrad)); 4638 PetscCall(DMGlobalToLocalEnd(dmGrad, grad, INSERT_VALUES, locGrad)); 4639 PetscCall(DMRestoreGlobalVector(dmGrad, &grad)); 4640 } 4641 /* Handle non-essential (e.g. outflow) boundary values */ 4642 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_FALSE, locX, time, faceGeometryFVM, cellGeometryFVM, locGrad)); 4643 } 4644 /* Loop over chunks */ 4645 if (useFEM) PetscCall(ISCreate(PETSC_COMM_SELF, &chunkIS)); 4646 numCells = cEnd - cStart; 4647 numChunks = 1; 4648 cellChunkSize = numCells / numChunks; 4649 faceChunkSize = (fEnd - fStart) / numChunks; 4650 numChunks = PetscMin(1, numCells); 4651 for (chunk = 0; chunk < numChunks; ++chunk) { 4652 PetscScalar *elemVec, *fluxL, *fluxR; 4653 PetscReal *vol; 4654 PetscFVFaceGeom *fgeom; 4655 PetscInt cS = cStart + chunk * cellChunkSize, cE = PetscMin(cS + cellChunkSize, cEnd), numCells = cE - cS, c; 4656 PetscInt fS = fStart + chunk * faceChunkSize, fE = PetscMin(fS + faceChunkSize, fEnd), numFaces = 0, face; 4657 4658 /* Extract field coefficients */ 4659 if (useFEM) { 4660 PetscCall(ISGetPointSubrange(chunkIS, cS, cE, cells)); 4661 PetscCall(DMPlexGetCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a)); 4662 PetscCall(DMGetWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec)); 4663 PetscCall(PetscArrayzero(elemVec, numCells * totDim)); 4664 } 4665 if (useFVM) { 4666 PetscCall(DMPlexGetFaceFields(dm, fS, fE, locX, locX_t, faceGeometryFVM, cellGeometryFVM, locGrad, &numFaces, &uL, &uR)); 4667 PetscCall(DMPlexGetFaceGeometry(dm, fS, fE, faceGeometryFVM, cellGeometryFVM, &numFaces, &fgeom, &vol)); 4668 PetscCall(DMGetWorkArray(dm, numFaces * totDim, MPIU_SCALAR, &fluxL)); 4669 PetscCall(DMGetWorkArray(dm, numFaces * totDim, MPIU_SCALAR, &fluxR)); 4670 PetscCall(PetscArrayzero(fluxL, numFaces * totDim)); 4671 PetscCall(PetscArrayzero(fluxR, numFaces * totDim)); 4672 } 4673 /* TODO We will interlace both our field coefficients (u, u_t, uL, uR, etc.) and our output (elemVec, fL, fR). I think this works */ 4674 /* Loop over fields */ 4675 for (f = 0; f < Nf; ++f) { 4676 PetscObject obj; 4677 PetscClassId id; 4678 PetscBool fimp; 4679 PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset; 4680 4681 key.field = f; 4682 PetscCall(PetscDSGetImplicit(ds, f, &fimp)); 4683 if (isImplicit != fimp) continue; 4684 PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 4685 PetscCall(PetscObjectGetClassId(obj, &id)); 4686 if (id == PETSCFE_CLASSID) { 4687 PetscFE fe = (PetscFE)obj; 4688 PetscFEGeom *geom = affineGeom ? affineGeom : geoms[f]; 4689 PetscFEGeom *chunkGeom = NULL; 4690 PetscQuadrature quad = affineQuad ? affineQuad : quads[f]; 4691 PetscInt Nq, Nb; 4692 4693 PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 4694 PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL)); 4695 PetscCall(PetscFEGetDimension(fe, &Nb)); 4696 blockSize = Nb; 4697 batchSize = numBlocks * blockSize; 4698 PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 4699 numChunks = numCells / (numBatches * batchSize); 4700 Ne = numChunks * numBatches * batchSize; 4701 Nr = numCells % (numBatches * batchSize); 4702 offset = numCells - Nr; 4703 /* Integrate FE residual to get elemVec (need fields at quadrature points) */ 4704 /* For FV, I think we use a P0 basis and the cell coefficients (for subdivided cells, we can tweak the basis tabulation to be the indicator function) */ 4705 PetscCall(PetscFEGeomGetChunk(geom, 0, offset, &chunkGeom)); 4706 PetscCall(PetscFEIntegrateResidual(ds, key, Ne, chunkGeom, u, u_t, dsAux, a, t, elemVec)); 4707 PetscCall(PetscFEGeomGetChunk(geom, offset, numCells, &chunkGeom)); 4708 PetscCall(PetscFEIntegrateResidual(ds, key, Nr, chunkGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, dsAux, &a[offset * totDimAux], t, &elemVec[offset * totDim])); 4709 PetscCall(PetscFEGeomRestoreChunk(geom, offset, numCells, &chunkGeom)); 4710 } else if (id == PETSCFV_CLASSID) { 4711 PetscFV fv = (PetscFV)obj; 4712 4713 Ne = numFaces; 4714 /* Riemann solve over faces (need fields at face centroids) */ 4715 /* We need to evaluate FE fields at those coordinates */ 4716 PetscCall(PetscFVIntegrateRHSFunction(fv, ds, f, Ne, fgeom, vol, uL, uR, fluxL, fluxR)); 4717 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f); 4718 } 4719 /* Loop over domain */ 4720 if (useFEM) { 4721 /* Add elemVec to locX */ 4722 for (c = cS; c < cE; ++c) { 4723 const PetscInt cell = cells ? cells[c] : c; 4724 const PetscInt cind = c - cStart; 4725 4726 if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, name, totDim, &elemVec[cind * totDim])); 4727 if (ghostLabel) { 4728 PetscInt ghostVal; 4729 4730 PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal)); 4731 if (ghostVal > 0) continue; 4732 } 4733 PetscCall(DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind * totDim], ADD_ALL_VALUES)); 4734 } 4735 } 4736 if (useFVM) { 4737 PetscScalar *fa; 4738 PetscInt iface; 4739 4740 PetscCall(VecGetArray(locF, &fa)); 4741 for (f = 0; f < Nf; ++f) { 4742 PetscFV fv; 4743 PetscObject obj; 4744 PetscClassId id; 4745 PetscInt foff, pdim; 4746 4747 PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 4748 PetscCall(PetscDSGetFieldOffset(ds, f, &foff)); 4749 PetscCall(PetscObjectGetClassId(obj, &id)); 4750 if (id != PETSCFV_CLASSID) continue; 4751 fv = (PetscFV)obj; 4752 PetscCall(PetscFVGetNumComponents(fv, &pdim)); 4753 /* Accumulate fluxes to cells */ 4754 for (face = fS, iface = 0; face < fE; ++face) { 4755 const PetscInt *scells; 4756 PetscScalar *fL = NULL, *fR = NULL; 4757 PetscInt ghost, d, nsupp, nchild; 4758 4759 PetscCall(DMLabelGetValue(ghostLabel, face, &ghost)); 4760 PetscCall(DMPlexGetSupportSize(dm, face, &nsupp)); 4761 PetscCall(DMPlexGetTreeChildren(dm, face, &nchild, NULL)); 4762 if (ghost >= 0 || nsupp > 2 || nchild > 0) continue; 4763 PetscCall(DMPlexGetSupport(dm, face, &scells)); 4764 PetscCall(DMLabelGetValue(ghostLabel, scells[0], &ghost)); 4765 if (ghost <= 0) PetscCall(DMPlexPointLocalFieldRef(dm, scells[0], f, fa, &fL)); 4766 PetscCall(DMLabelGetValue(ghostLabel, scells[1], &ghost)); 4767 if (ghost <= 0) PetscCall(DMPlexPointLocalFieldRef(dm, scells[1], f, fa, &fR)); 4768 for (d = 0; d < pdim; ++d) { 4769 if (fL) fL[d] -= fluxL[iface * totDim + foff + d]; 4770 if (fR) fR[d] += fluxR[iface * totDim + foff + d]; 4771 } 4772 ++iface; 4773 } 4774 } 4775 PetscCall(VecRestoreArray(locF, &fa)); 4776 } 4777 /* Handle time derivative */ 4778 if (locX_t) { 4779 PetscScalar *x_t, *fa; 4780 4781 PetscCall(VecGetArray(locF, &fa)); 4782 PetscCall(VecGetArray(locX_t, &x_t)); 4783 for (f = 0; f < Nf; ++f) { 4784 PetscFV fv; 4785 PetscObject obj; 4786 PetscClassId id; 4787 PetscInt pdim, d; 4788 4789 PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 4790 PetscCall(PetscObjectGetClassId(obj, &id)); 4791 if (id != PETSCFV_CLASSID) continue; 4792 fv = (PetscFV)obj; 4793 PetscCall(PetscFVGetNumComponents(fv, &pdim)); 4794 for (c = cS; c < cE; ++c) { 4795 const PetscInt cell = cells ? cells[c] : c; 4796 PetscScalar *u_t, *r; 4797 4798 if (ghostLabel) { 4799 PetscInt ghostVal; 4800 4801 PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal)); 4802 if (ghostVal > 0) continue; 4803 } 4804 PetscCall(DMPlexPointLocalFieldRead(dm, cell, f, x_t, &u_t)); 4805 PetscCall(DMPlexPointLocalFieldRef(dm, cell, f, fa, &r)); 4806 for (d = 0; d < pdim; ++d) r[d] += u_t[d]; 4807 } 4808 } 4809 PetscCall(VecRestoreArray(locX_t, &x_t)); 4810 PetscCall(VecRestoreArray(locF, &fa)); 4811 } 4812 if (useFEM) { 4813 PetscCall(DMPlexRestoreCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a)); 4814 PetscCall(DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec)); 4815 } 4816 if (useFVM) { 4817 PetscCall(DMPlexRestoreFaceFields(dm, fS, fE, locX, locX_t, faceGeometryFVM, cellGeometryFVM, locGrad, &numFaces, &uL, &uR)); 4818 PetscCall(DMPlexRestoreFaceGeometry(dm, fS, fE, faceGeometryFVM, cellGeometryFVM, &numFaces, &fgeom, &vol)); 4819 PetscCall(DMRestoreWorkArray(dm, numFaces * totDim, MPIU_SCALAR, &fluxL)); 4820 PetscCall(DMRestoreWorkArray(dm, numFaces * totDim, MPIU_SCALAR, &fluxR)); 4821 if (dmGrad) PetscCall(DMRestoreLocalVector(dmGrad, &locGrad)); 4822 } 4823 } 4824 if (useFEM) PetscCall(ISDestroy(&chunkIS)); 4825 PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 4826 4827 if (useFEM) { 4828 PetscCall(DMPlexComputeBdResidual_Internal(dm, locX, locX_t, t, locF, user)); 4829 4830 if (maxDegree <= 1) { 4831 PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom)); 4832 PetscCall(PetscQuadratureDestroy(&affineQuad)); 4833 } else { 4834 for (f = 0; f < Nf; ++f) { 4835 PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f])); 4836 PetscCall(PetscQuadratureDestroy(&quads[f])); 4837 } 4838 PetscCall(PetscFree2(quads, geoms)); 4839 } 4840 } 4841 4842 /* FEM */ 4843 /* 1: Get sizes from dm and dmAux */ 4844 /* 2: Get geometric data */ 4845 /* 3: Handle boundary values */ 4846 /* 4: Loop over domain */ 4847 /* Extract coefficients */ 4848 /* Loop over fields */ 4849 /* Set tiling for FE*/ 4850 /* Integrate FE residual to get elemVec */ 4851 /* Loop over subdomain */ 4852 /* Loop over quad points */ 4853 /* Transform coords to real space */ 4854 /* Evaluate field and aux fields at point */ 4855 /* Evaluate residual at point */ 4856 /* Transform residual to real space */ 4857 /* Add residual to elemVec */ 4858 /* Loop over domain */ 4859 /* Add elemVec to locX */ 4860 4861 /* FVM */ 4862 /* Get geometric data */ 4863 /* If using gradients */ 4864 /* Compute gradient data */ 4865 /* Loop over domain faces */ 4866 /* Count computational faces */ 4867 /* Reconstruct cell gradient */ 4868 /* Loop over domain cells */ 4869 /* Limit cell gradients */ 4870 /* Handle boundary values */ 4871 /* Loop over domain faces */ 4872 /* Read out field, centroid, normal, volume for each side of face */ 4873 /* Riemann solve over faces */ 4874 /* Loop over domain faces */ 4875 /* Accumulate fluxes to cells */ 4876 /* TODO Change printFEM to printDisc here */ 4877 if (mesh->printFEM) { 4878 Vec locFbc; 4879 PetscInt pStart, pEnd, p, maxDof; 4880 PetscScalar *zeroes; 4881 4882 PetscCall(VecDuplicate(locF, &locFbc)); 4883 PetscCall(VecCopy(locF, locFbc)); 4884 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 4885 PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 4886 PetscCall(PetscCalloc1(maxDof, &zeroes)); 4887 for (p = pStart; p < pEnd; p++) PetscCall(VecSetValuesSection(locFbc, section, p, zeroes, INSERT_BC_VALUES)); 4888 PetscCall(PetscFree(zeroes)); 4889 PetscCall(DMPrintLocalVec(dm, name, mesh->printTol, locFbc)); 4890 PetscCall(VecDestroy(&locFbc)); 4891 } 4892 PetscCall(PetscLogEventEnd(DMPLEX_ResidualFEM, dm, 0, 0, 0)); 4893 PetscFunctionReturn(PETSC_SUCCESS); 4894 } 4895 4896 /* 4897 1) Allow multiple kernels for BdResidual for hybrid DS 4898 4899 DONE 2) Get out dsAux for either side at the same time as cohesive cell dsAux 4900 4901 DONE 3) Change DMGetCellFields() to get different aux data a[] for each side 4902 - I think I just need to replace a[] with the closure from each face 4903 4904 4) Run both kernels for each non-hybrid field with correct dsAux, and then hybrid field as before 4905 */ 4906 PetscErrorCode DMPlexComputeResidual_Hybrid_Internal(DM dm, PetscFormKey key[], IS cellIS, PetscReal time, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user) 4907 { 4908 DM_Plex *mesh = (DM_Plex *)dm->data; 4909 const char *name = "Hybrid Residual"; 4910 DM dmAux[3] = {NULL, NULL, NULL}; 4911 DMLabel ghostLabel = NULL; 4912 PetscDS ds = NULL; 4913 PetscDS dsAux[3] = {NULL, NULL, NULL}; 4914 Vec locA[3] = {NULL, NULL, NULL}; 4915 PetscScalar *a[3] = {NULL, NULL, NULL}; 4916 PetscSection section = NULL; 4917 DMField coordField = NULL; 4918 PetscScalar *u = NULL, *u_t; 4919 PetscScalar *elemVec; 4920 IS chunkIS; 4921 const PetscInt *cells; 4922 PetscInt *faces; 4923 PetscInt cStart, cEnd, numCells; 4924 PetscInt Nf, f, totDim, totDimAux[3], numChunks, cellChunkSize, chunk; 4925 PetscInt maxDegree = PETSC_MAX_INT; 4926 PetscQuadrature affineQuad = NULL, *quads = NULL; 4927 PetscFEGeom *affineGeom = NULL, **geoms = NULL; 4928 4929 PetscFunctionBegin; 4930 if (!cellIS) PetscFunctionReturn(PETSC_SUCCESS); 4931 PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 4932 PetscCall(ISGetLocalSize(cellIS, &numCells)); 4933 if (cStart >= cEnd) PetscFunctionReturn(PETSC_SUCCESS); 4934 if ((key[0].label == key[1].label) && (key[0].value == key[1].value) && (key[0].part == key[1].part)) { 4935 const char *name; 4936 PetscCall(PetscObjectGetName((PetscObject)key[0].label, &name)); 4937 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Form keys for each side of a cohesive surface must be different (%s, %" PetscInt_FMT ", %" PetscInt_FMT ")", name, key[0].value, key[0].part); 4938 } 4939 PetscCall(PetscLogEventBegin(DMPLEX_ResidualFEM, dm, 0, 0, 0)); 4940 /* TODO The places where we have to use isFE are probably the member functions for the PetscDisc class */ 4941 /* FEM */ 4942 /* 1: Get sizes from dm and dmAux */ 4943 PetscCall(DMGetSection(dm, §ion)); 4944 PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 4945 PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds)); 4946 PetscCall(PetscDSGetNumFields(ds, &Nf)); 4947 PetscCall(PetscDSGetTotalDimension(ds, &totDim)); 4948 PetscCall(DMGetAuxiliaryVec(dm, key[2].label, key[2].value, key[2].part, &locA[2])); 4949 if (locA[2]) { 4950 const PetscInt cellStart = cells ? cells[cStart] : cStart; 4951 4952 PetscCall(VecGetDM(locA[2], &dmAux[2])); 4953 PetscCall(DMGetCellDS(dmAux[2], cellStart, &dsAux[2])); 4954 PetscCall(PetscDSGetTotalDimension(dsAux[2], &totDimAux[2])); 4955 { 4956 const PetscInt *cone; 4957 PetscInt c; 4958 4959 PetscCall(DMPlexGetCone(dm, cellStart, &cone)); 4960 for (c = 0; c < 2; ++c) { 4961 const PetscInt *support; 4962 PetscInt ssize, s; 4963 4964 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 4965 PetscCall(DMPlexGetSupportSize(dm, cone[c], &ssize)); 4966 PetscCheck(ssize == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " from cell %" PetscInt_FMT " has support size %" PetscInt_FMT " != 2", cone[c], cellStart, ssize); 4967 if (support[0] == cellStart) s = 1; 4968 else if (support[1] == cellStart) s = 0; 4969 else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " does not have cell %" PetscInt_FMT " in its support", cone[c], cellStart); 4970 PetscCall(DMGetAuxiliaryVec(dm, key[c].label, key[c].value, key[c].part, &locA[c])); 4971 PetscCheck(locA[c], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must have auxiliary vector for (%p, %" PetscInt_FMT ", %" PetscInt_FMT ")", (void *)key[c].label, key[c].value, key[c].part); 4972 if (locA[c]) PetscCall(VecGetDM(locA[c], &dmAux[c])); 4973 else dmAux[c] = dmAux[2]; 4974 PetscCall(DMGetCellDS(dmAux[c], support[s], &dsAux[c])); 4975 PetscCall(PetscDSGetTotalDimension(dsAux[c], &totDimAux[c])); 4976 } 4977 } 4978 } 4979 /* 2: Setup geometric data */ 4980 PetscCall(DMGetCoordinateField(dm, &coordField)); 4981 PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 4982 if (maxDegree > 1) { 4983 PetscCall(PetscCalloc2(Nf, &quads, Nf, &geoms)); 4984 for (f = 0; f < Nf; ++f) { 4985 PetscFE fe; 4986 4987 PetscCall(PetscDSGetDiscretization(ds, f, (PetscObject *)&fe)); 4988 if (fe) { 4989 PetscCall(PetscFEGetQuadrature(fe, &quads[f])); 4990 PetscCall(PetscObjectReference((PetscObject)quads[f])); 4991 } 4992 } 4993 } 4994 /* Loop over chunks */ 4995 cellChunkSize = numCells; 4996 numChunks = !numCells ? 0 : PetscCeilReal(((PetscReal)numCells) / cellChunkSize); 4997 PetscCall(PetscCalloc1(1 * cellChunkSize, &faces)); 4998 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 1 * cellChunkSize, faces, PETSC_USE_POINTER, &chunkIS)); 4999 /* Extract field coefficients */ 5000 /* NOTE This needs the end cap faces to have identical orientations */ 5001 PetscCall(DMPlexGetCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2])); 5002 PetscCall(DMPlexGetHybridAuxFields(dm, dmAux, dsAux, cellIS, locA, a)); 5003 PetscCall(DMGetWorkArray(dm, cellChunkSize * totDim, MPIU_SCALAR, &elemVec)); 5004 for (chunk = 0; chunk < numChunks; ++chunk) { 5005 PetscInt cS = cStart + chunk * cellChunkSize, cE = PetscMin(cS + cellChunkSize, cEnd), numCells = cE - cS, c; 5006 5007 PetscCall(PetscMemzero(elemVec, cellChunkSize * totDim * sizeof(PetscScalar))); 5008 /* Get faces */ 5009 for (c = cS; c < cE; ++c) { 5010 const PetscInt cell = cells ? cells[c] : c; 5011 const PetscInt *cone; 5012 PetscCall(DMPlexGetCone(dm, cell, &cone)); 5013 faces[0 * cellChunkSize + (c - cS)] = cone[0]; 5014 /*faces[1*cellChunkSize+(c-cS)] = cone[1];*/ 5015 } 5016 PetscCall(ISGeneralSetIndices(chunkIS, 1 * cellChunkSize, faces, PETSC_USE_POINTER)); 5017 /* Get geometric data */ 5018 if (maxDegree <= 1) { 5019 if (!affineQuad) PetscCall(DMFieldCreateDefaultQuadrature(coordField, chunkIS, &affineQuad)); 5020 if (affineQuad) PetscCall(DMSNESGetFEGeom(coordField, chunkIS, affineQuad, PETSC_TRUE, &affineGeom)); 5021 } else { 5022 for (f = 0; f < Nf; ++f) { 5023 if (quads[f]) PetscCall(DMSNESGetFEGeom(coordField, chunkIS, quads[f], PETSC_TRUE, &geoms[f])); 5024 } 5025 } 5026 /* Loop over fields */ 5027 for (f = 0; f < Nf; ++f) { 5028 PetscFE fe; 5029 PetscFEGeom *geom = affineGeom ? affineGeom : geoms[f]; 5030 PetscFEGeom *chunkGeom = NULL, *remGeom = NULL; 5031 PetscQuadrature quad = affineQuad ? affineQuad : quads[f]; 5032 PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset, Nq, Nb; 5033 PetscBool isCohesiveField; 5034 5035 PetscCall(PetscDSGetDiscretization(ds, f, (PetscObject *)&fe)); 5036 if (!fe) continue; 5037 PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 5038 PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL)); 5039 PetscCall(PetscFEGetDimension(fe, &Nb)); 5040 blockSize = Nb; 5041 batchSize = numBlocks * blockSize; 5042 PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 5043 numChunks = numCells / (numBatches * batchSize); 5044 Ne = numChunks * numBatches * batchSize; 5045 Nr = numCells % (numBatches * batchSize); 5046 offset = numCells - Nr; 5047 PetscCall(PetscFEGeomGetChunk(geom, 0, offset, &chunkGeom)); 5048 PetscCall(PetscFEGeomGetChunk(geom, offset, numCells, &remGeom)); 5049 PetscCall(PetscDSGetCohesive(ds, f, &isCohesiveField)); 5050 chunkGeom->isCohesive = remGeom->isCohesive = PETSC_TRUE; 5051 key[0].field = f; 5052 key[1].field = f; 5053 key[2].field = f; 5054 PetscCall(PetscFEIntegrateHybridResidual(ds, key[0], 0, Ne, chunkGeom, u, u_t, dsAux[0], a[0], t, elemVec)); 5055 PetscCall(PetscFEIntegrateHybridResidual(ds, key[0], 0, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, dsAux[0], &a[0][offset * totDimAux[0]], t, &elemVec[offset * totDim])); 5056 PetscCall(PetscFEIntegrateHybridResidual(ds, key[1], 1, Ne, chunkGeom, u, u_t, dsAux[1], a[1], t, elemVec)); 5057 PetscCall(PetscFEIntegrateHybridResidual(ds, key[1], 1, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, dsAux[1], &a[1][offset * totDimAux[1]], t, &elemVec[offset * totDim])); 5058 PetscCall(PetscFEIntegrateHybridResidual(ds, key[2], 2, Ne, chunkGeom, u, u_t, dsAux[2], a[2], t, elemVec)); 5059 PetscCall(PetscFEIntegrateHybridResidual(ds, key[2], 2, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, dsAux[2], &a[2][offset * totDimAux[2]], t, &elemVec[offset * totDim])); 5060 PetscCall(PetscFEGeomRestoreChunk(geom, offset, numCells, &remGeom)); 5061 PetscCall(PetscFEGeomRestoreChunk(geom, 0, offset, &chunkGeom)); 5062 } 5063 /* Add elemVec to locX */ 5064 for (c = cS; c < cE; ++c) { 5065 const PetscInt cell = cells ? cells[c] : c; 5066 const PetscInt cind = c - cStart; 5067 5068 if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, name, totDim, &elemVec[cind * totDim])); 5069 if (ghostLabel) { 5070 PetscInt ghostVal; 5071 5072 PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal)); 5073 if (ghostVal > 0) continue; 5074 } 5075 PetscCall(DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind * totDim], ADD_ALL_VALUES)); 5076 } 5077 } 5078 PetscCall(DMPlexRestoreCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2])); 5079 PetscCall(DMPlexRestoreHybridAuxFields(dmAux, dsAux, cellIS, locA, a)); 5080 PetscCall(DMRestoreWorkArray(dm, numCells * totDim, MPIU_SCALAR, &elemVec)); 5081 PetscCall(PetscFree(faces)); 5082 PetscCall(ISDestroy(&chunkIS)); 5083 PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 5084 if (maxDegree <= 1) { 5085 PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom)); 5086 PetscCall(PetscQuadratureDestroy(&affineQuad)); 5087 } else { 5088 for (f = 0; f < Nf; ++f) { 5089 if (geoms) PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f])); 5090 if (quads) PetscCall(PetscQuadratureDestroy(&quads[f])); 5091 } 5092 PetscCall(PetscFree2(quads, geoms)); 5093 } 5094 if (mesh->printFEM) { 5095 Vec locFbc; 5096 PetscInt pStart, pEnd, p, maxDof; 5097 PetscScalar *zeroes; 5098 5099 PetscCall(VecDuplicate(locF, &locFbc)); 5100 PetscCall(VecCopy(locF, locFbc)); 5101 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 5102 PetscCall(PetscSectionGetMaxDof(section, &maxDof)); 5103 PetscCall(PetscCalloc1(maxDof, &zeroes)); 5104 for (p = pStart; p < pEnd; p++) PetscCall(VecSetValuesSection(locFbc, section, p, zeroes, INSERT_BC_VALUES)); 5105 PetscCall(PetscFree(zeroes)); 5106 PetscCall(DMPrintLocalVec(dm, name, mesh->printTol, locFbc)); 5107 PetscCall(VecDestroy(&locFbc)); 5108 } 5109 PetscCall(PetscLogEventEnd(DMPLEX_ResidualFEM, dm, 0, 0, 0)); 5110 PetscFunctionReturn(PETSC_SUCCESS); 5111 } 5112 5113 PetscErrorCode DMPlexComputeBdJacobian_Single_Internal(DM dm, PetscReal t, PetscWeakForm wf, DMLabel label, PetscInt numValues, const PetscInt values[], PetscInt fieldI, Vec locX, Vec locX_t, PetscReal X_tShift, Mat Jac, Mat JacP, DMField coordField, IS facetIS) 5114 { 5115 DM_Plex *mesh = (DM_Plex *)dm->data; 5116 DM plex = NULL, plexA = NULL, tdm; 5117 DMEnclosureType encAux; 5118 PetscDS prob, probAux = NULL; 5119 PetscSection section, sectionAux = NULL; 5120 PetscSection globalSection; 5121 Vec locA = NULL, tv; 5122 PetscScalar *u = NULL, *u_t = NULL, *a = NULL, *elemMat = NULL; 5123 PetscInt v; 5124 PetscInt Nf, totDim, totDimAux = 0; 5125 PetscBool transform; 5126 5127 PetscFunctionBegin; 5128 PetscCall(DMConvert(dm, DMPLEX, &plex)); 5129 PetscCall(DMHasBasisTransform(dm, &transform)); 5130 PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm)); 5131 PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 5132 PetscCall(DMGetLocalSection(dm, §ion)); 5133 PetscCall(DMGetDS(dm, &prob)); 5134 PetscCall(PetscDSGetNumFields(prob, &Nf)); 5135 PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 5136 PetscCall(DMGetAuxiliaryVec(dm, label, values[0], 0, &locA)); 5137 if (locA) { 5138 DM dmAux; 5139 5140 PetscCall(VecGetDM(locA, &dmAux)); 5141 PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 5142 PetscCall(DMConvert(dmAux, DMPLEX, &plexA)); 5143 PetscCall(DMGetDS(plexA, &probAux)); 5144 PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 5145 PetscCall(DMGetLocalSection(plexA, §ionAux)); 5146 } 5147 5148 PetscCall(DMGetGlobalSection(dm, &globalSection)); 5149 for (v = 0; v < numValues; ++v) { 5150 PetscFEGeom *fgeom; 5151 PetscInt maxDegree; 5152 PetscQuadrature qGeom = NULL; 5153 IS pointIS; 5154 const PetscInt *points; 5155 PetscFormKey key; 5156 PetscInt numFaces, face, Nq; 5157 5158 key.label = label; 5159 key.value = values[v]; 5160 key.part = 0; 5161 PetscCall(DMLabelGetStratumIS(label, values[v], &pointIS)); 5162 if (!pointIS) continue; /* No points with that id on this process */ 5163 { 5164 IS isectIS; 5165 5166 /* TODO: Special cases of ISIntersect where it is quick to check a prior if one is a superset of the other */ 5167 PetscCall(ISIntersect_Caching_Internal(facetIS, pointIS, &isectIS)); 5168 PetscCall(ISDestroy(&pointIS)); 5169 pointIS = isectIS; 5170 } 5171 PetscCall(ISGetLocalSize(pointIS, &numFaces)); 5172 PetscCall(ISGetIndices(pointIS, &points)); 5173 PetscCall(PetscMalloc4(numFaces * totDim, &u, locX_t ? numFaces * totDim : 0, &u_t, numFaces * totDim * totDim, &elemMat, locA ? numFaces * totDimAux : 0, &a)); 5174 PetscCall(DMFieldGetDegree(coordField, pointIS, NULL, &maxDegree)); 5175 if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, pointIS, &qGeom)); 5176 if (!qGeom) { 5177 PetscFE fe; 5178 5179 PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe)); 5180 PetscCall(PetscFEGetFaceQuadrature(fe, &qGeom)); 5181 PetscCall(PetscObjectReference((PetscObject)qGeom)); 5182 } 5183 PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL)); 5184 PetscCall(DMSNESGetFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 5185 for (face = 0; face < numFaces; ++face) { 5186 const PetscInt point = points[face], *support; 5187 PetscScalar *x = NULL; 5188 PetscInt i; 5189 5190 PetscCall(DMPlexGetSupport(dm, point, &support)); 5191 PetscCall(DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x)); 5192 for (i = 0; i < totDim; ++i) u[face * totDim + i] = x[i]; 5193 PetscCall(DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x)); 5194 if (locX_t) { 5195 PetscCall(DMPlexVecGetClosure(plex, section, locX_t, support[0], NULL, &x)); 5196 for (i = 0; i < totDim; ++i) u_t[face * totDim + i] = x[i]; 5197 PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, support[0], NULL, &x)); 5198 } 5199 if (locA) { 5200 PetscInt subp; 5201 PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp)); 5202 PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x)); 5203 for (i = 0; i < totDimAux; ++i) a[face * totDimAux + i] = x[i]; 5204 PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x)); 5205 } 5206 } 5207 PetscCall(PetscArrayzero(elemMat, numFaces * totDim * totDim)); 5208 { 5209 PetscFE fe; 5210 PetscInt Nb; 5211 /* Conforming batches */ 5212 PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize; 5213 /* Remainder */ 5214 PetscFEGeom *chunkGeom = NULL; 5215 PetscInt fieldJ, Nr, offset; 5216 5217 PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe)); 5218 PetscCall(PetscFEGetDimension(fe, &Nb)); 5219 PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 5220 blockSize = Nb; 5221 batchSize = numBlocks * blockSize; 5222 PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 5223 numChunks = numFaces / (numBatches * batchSize); 5224 Ne = numChunks * numBatches * batchSize; 5225 Nr = numFaces % (numBatches * batchSize); 5226 offset = numFaces - Nr; 5227 PetscCall(PetscFEGeomGetChunk(fgeom, 0, offset, &chunkGeom)); 5228 for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 5229 key.field = fieldI * Nf + fieldJ; 5230 PetscCall(PetscFEIntegrateBdJacobian(prob, wf, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat)); 5231 } 5232 PetscCall(PetscFEGeomGetChunk(fgeom, offset, numFaces, &chunkGeom)); 5233 for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 5234 key.field = fieldI * Nf + fieldJ; 5235 PetscCall(PetscFEIntegrateBdJacobian(prob, wf, key, Nr, chunkGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, probAux, a ? &a[offset * totDimAux] : NULL, t, X_tShift, &elemMat[offset * totDim * totDim])); 5236 } 5237 PetscCall(PetscFEGeomRestoreChunk(fgeom, offset, numFaces, &chunkGeom)); 5238 } 5239 for (face = 0; face < numFaces; ++face) { 5240 const PetscInt point = points[face], *support; 5241 5242 /* Transform to global basis before insertion in Jacobian */ 5243 PetscCall(DMPlexGetSupport(plex, point, &support)); 5244 if (transform) PetscCall(DMPlexBasisTransformPointTensor_Internal(dm, tdm, tv, support[0], PETSC_TRUE, totDim, &elemMat[face * totDim * totDim])); 5245 if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(point, "BdJacobian", totDim, totDim, &elemMat[face * totDim * totDim])); 5246 PetscCall(DMPlexMatSetClosure(plex, section, globalSection, JacP, support[0], &elemMat[face * totDim * totDim], ADD_VALUES)); 5247 } 5248 PetscCall(DMSNESRestoreFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 5249 PetscCall(PetscQuadratureDestroy(&qGeom)); 5250 PetscCall(ISRestoreIndices(pointIS, &points)); 5251 PetscCall(ISDestroy(&pointIS)); 5252 PetscCall(PetscFree4(u, u_t, elemMat, a)); 5253 } 5254 if (plex) PetscCall(DMDestroy(&plex)); 5255 if (plexA) PetscCall(DMDestroy(&plexA)); 5256 PetscFunctionReturn(PETSC_SUCCESS); 5257 } 5258 5259 PetscErrorCode DMPlexComputeBdJacobianSingle(DM dm, PetscReal t, PetscWeakForm wf, DMLabel label, PetscInt numValues, const PetscInt values[], PetscInt field, Vec locX, Vec locX_t, PetscReal X_tShift, Mat Jac, Mat JacP) 5260 { 5261 DMField coordField; 5262 DMLabel depthLabel; 5263 IS facetIS; 5264 PetscInt dim; 5265 5266 PetscFunctionBegin; 5267 PetscCall(DMGetDimension(dm, &dim)); 5268 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 5269 PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 5270 PetscCall(DMGetCoordinateField(dm, &coordField)); 5271 PetscCall(DMPlexComputeBdJacobian_Single_Internal(dm, t, wf, label, numValues, values, field, locX, locX_t, X_tShift, Jac, JacP, coordField, facetIS)); 5272 PetscCall(ISDestroy(&facetIS)); 5273 PetscFunctionReturn(PETSC_SUCCESS); 5274 } 5275 5276 PetscErrorCode DMPlexComputeBdJacobian_Internal(DM dm, Vec locX, Vec locX_t, PetscReal t, PetscReal X_tShift, Mat Jac, Mat JacP, void *user) 5277 { 5278 PetscDS prob; 5279 PetscInt dim, numBd, bd; 5280 DMLabel depthLabel; 5281 DMField coordField = NULL; 5282 IS facetIS; 5283 5284 PetscFunctionBegin; 5285 PetscCall(DMGetDS(dm, &prob)); 5286 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 5287 PetscCall(DMGetDimension(dm, &dim)); 5288 PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 5289 PetscCall(PetscDSGetNumBoundary(prob, &numBd)); 5290 PetscCall(DMGetCoordinateField(dm, &coordField)); 5291 for (bd = 0; bd < numBd; ++bd) { 5292 PetscWeakForm wf; 5293 DMBoundaryConditionType type; 5294 DMLabel label; 5295 const PetscInt *values; 5296 PetscInt fieldI, numValues; 5297 PetscObject obj; 5298 PetscClassId id; 5299 5300 PetscCall(PetscDSGetBoundary(prob, bd, &wf, &type, NULL, &label, &numValues, &values, &fieldI, NULL, NULL, NULL, NULL, NULL)); 5301 if (type & DM_BC_ESSENTIAL) continue; 5302 PetscCall(PetscDSGetDiscretization(prob, fieldI, &obj)); 5303 PetscCall(PetscObjectGetClassId(obj, &id)); 5304 if (id != PETSCFE_CLASSID) continue; 5305 PetscCall(DMPlexComputeBdJacobian_Single_Internal(dm, t, wf, label, numValues, values, fieldI, locX, locX_t, X_tShift, Jac, JacP, coordField, facetIS)); 5306 } 5307 PetscCall(ISDestroy(&facetIS)); 5308 PetscFunctionReturn(PETSC_SUCCESS); 5309 } 5310 5311 PetscErrorCode DMPlexComputeJacobian_Internal(DM dm, PetscFormKey key, IS cellIS, PetscReal t, PetscReal X_tShift, Vec X, Vec X_t, Mat Jac, Mat JacP, void *user) 5312 { 5313 DM_Plex *mesh = (DM_Plex *)dm->data; 5314 const char *name = "Jacobian"; 5315 DM dmAux = NULL, plex, tdm; 5316 DMEnclosureType encAux; 5317 Vec A, tv; 5318 DMField coordField; 5319 PetscDS prob, probAux = NULL; 5320 PetscSection section, globalSection, sectionAux; 5321 PetscScalar *elemMat, *elemMatP, *elemMatD, *u, *u_t, *a = NULL; 5322 const PetscInt *cells; 5323 PetscInt Nf, fieldI, fieldJ; 5324 PetscInt totDim, totDimAux = 0, cStart, cEnd, numCells, c; 5325 PetscBool hasJac = PETSC_FALSE, hasPrec = PETSC_FALSE, hasDyn, hasFV = PETSC_FALSE, transform; 5326 5327 PetscFunctionBegin; 5328 if (!cellIS) goto end; 5329 PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 5330 PetscCall(ISGetLocalSize(cellIS, &numCells)); 5331 if (cStart >= cEnd) goto end; 5332 PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 5333 PetscCall(DMHasBasisTransform(dm, &transform)); 5334 PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm)); 5335 PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 5336 PetscCall(DMGetLocalSection(dm, §ion)); 5337 PetscCall(DMGetGlobalSection(dm, &globalSection)); 5338 PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob)); 5339 PetscCall(PetscDSGetNumFields(prob, &Nf)); 5340 PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 5341 PetscCall(PetscDSHasJacobian(prob, &hasJac)); 5342 PetscCall(PetscDSHasJacobianPreconditioner(prob, &hasPrec)); 5343 /* user passed in the same matrix, avoid double contributions and 5344 only assemble the Jacobian */ 5345 if (hasJac && Jac == JacP) hasPrec = PETSC_FALSE; 5346 PetscCall(PetscDSHasDynamicJacobian(prob, &hasDyn)); 5347 hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE; 5348 PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &A)); 5349 if (A) { 5350 PetscCall(VecGetDM(A, &dmAux)); 5351 PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 5352 PetscCall(DMConvert(dmAux, DMPLEX, &plex)); 5353 PetscCall(DMGetLocalSection(plex, §ionAux)); 5354 PetscCall(DMGetDS(dmAux, &probAux)); 5355 PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 5356 } 5357 PetscCall(PetscMalloc5(numCells * totDim, &u, X_t ? numCells * totDim : 0, &u_t, hasJac ? numCells * totDim * totDim : 0, &elemMat, hasPrec ? numCells * totDim * totDim : 0, &elemMatP, hasDyn ? numCells * totDim * totDim : 0, &elemMatD)); 5358 if (dmAux) PetscCall(PetscMalloc1(numCells * totDimAux, &a)); 5359 PetscCall(DMGetCoordinateField(dm, &coordField)); 5360 for (c = cStart; c < cEnd; ++c) { 5361 const PetscInt cell = cells ? cells[c] : c; 5362 const PetscInt cind = c - cStart; 5363 PetscScalar *x = NULL, *x_t = NULL; 5364 PetscInt i; 5365 5366 PetscCall(DMPlexVecGetClosure(dm, section, X, cell, NULL, &x)); 5367 for (i = 0; i < totDim; ++i) u[cind * totDim + i] = x[i]; 5368 PetscCall(DMPlexVecRestoreClosure(dm, section, X, cell, NULL, &x)); 5369 if (X_t) { 5370 PetscCall(DMPlexVecGetClosure(dm, section, X_t, cell, NULL, &x_t)); 5371 for (i = 0; i < totDim; ++i) u_t[cind * totDim + i] = x_t[i]; 5372 PetscCall(DMPlexVecRestoreClosure(dm, section, X_t, cell, NULL, &x_t)); 5373 } 5374 if (dmAux) { 5375 PetscInt subcell; 5376 PetscCall(DMGetEnclosurePoint(dmAux, dm, encAux, cell, &subcell)); 5377 PetscCall(DMPlexVecGetClosure(plex, sectionAux, A, subcell, NULL, &x)); 5378 for (i = 0; i < totDimAux; ++i) a[cind * totDimAux + i] = x[i]; 5379 PetscCall(DMPlexVecRestoreClosure(plex, sectionAux, A, subcell, NULL, &x)); 5380 } 5381 } 5382 if (hasJac) PetscCall(PetscArrayzero(elemMat, numCells * totDim * totDim)); 5383 if (hasPrec) PetscCall(PetscArrayzero(elemMatP, numCells * totDim * totDim)); 5384 if (hasDyn) PetscCall(PetscArrayzero(elemMatD, numCells * totDim * totDim)); 5385 for (fieldI = 0; fieldI < Nf; ++fieldI) { 5386 PetscClassId id; 5387 PetscFE fe; 5388 PetscQuadrature qGeom = NULL; 5389 PetscInt Nb; 5390 /* Conforming batches */ 5391 PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize; 5392 /* Remainder */ 5393 PetscInt Nr, offset, Nq; 5394 PetscInt maxDegree; 5395 PetscFEGeom *cgeomFEM, *chunkGeom = NULL, *remGeom = NULL; 5396 5397 PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe)); 5398 PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 5399 if (id == PETSCFV_CLASSID) { 5400 hasFV = PETSC_TRUE; 5401 continue; 5402 } 5403 PetscCall(PetscFEGetDimension(fe, &Nb)); 5404 PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 5405 PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 5406 if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &qGeom)); 5407 if (!qGeom) { 5408 PetscCall(PetscFEGetQuadrature(fe, &qGeom)); 5409 PetscCall(PetscObjectReference((PetscObject)qGeom)); 5410 } 5411 PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL)); 5412 PetscCall(DMSNESGetFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 5413 blockSize = Nb; 5414 batchSize = numBlocks * blockSize; 5415 PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 5416 numChunks = numCells / (numBatches * batchSize); 5417 Ne = numChunks * numBatches * batchSize; 5418 Nr = numCells % (numBatches * batchSize); 5419 offset = numCells - Nr; 5420 PetscCall(PetscFEGeomGetChunk(cgeomFEM, 0, offset, &chunkGeom)); 5421 PetscCall(PetscFEGeomGetChunk(cgeomFEM, offset, numCells, &remGeom)); 5422 for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 5423 key.field = fieldI * Nf + fieldJ; 5424 if (hasJac) { 5425 PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat)); 5426 PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, probAux, &a[offset * totDimAux], t, X_tShift, &elemMat[offset * totDim * totDim])); 5427 } 5428 if (hasPrec) { 5429 PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatP)); 5430 PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, key, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, probAux, &a[offset * totDimAux], t, X_tShift, &elemMatP[offset * totDim * totDim])); 5431 } 5432 if (hasDyn) { 5433 PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatD)); 5434 PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, probAux, &a[offset * totDimAux], t, X_tShift, &elemMatD[offset * totDim * totDim])); 5435 } 5436 } 5437 PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, offset, numCells, &remGeom)); 5438 PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, 0, offset, &chunkGeom)); 5439 PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 5440 PetscCall(PetscQuadratureDestroy(&qGeom)); 5441 } 5442 /* Add contribution from X_t */ 5443 if (hasDyn) { 5444 for (c = 0; c < numCells * totDim * totDim; ++c) elemMat[c] += X_tShift * elemMatD[c]; 5445 } 5446 if (hasFV) { 5447 PetscClassId id; 5448 PetscFV fv; 5449 PetscInt offsetI, NcI, NbI = 1, fc, f; 5450 5451 for (fieldI = 0; fieldI < Nf; ++fieldI) { 5452 PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fv)); 5453 PetscCall(PetscDSGetFieldOffset(prob, fieldI, &offsetI)); 5454 PetscCall(PetscObjectGetClassId((PetscObject)fv, &id)); 5455 if (id != PETSCFV_CLASSID) continue; 5456 /* Put in the identity */ 5457 PetscCall(PetscFVGetNumComponents(fv, &NcI)); 5458 for (c = cStart; c < cEnd; ++c) { 5459 const PetscInt cind = c - cStart; 5460 const PetscInt eOffset = cind * totDim * totDim; 5461 for (fc = 0; fc < NcI; ++fc) { 5462 for (f = 0; f < NbI; ++f) { 5463 const PetscInt i = offsetI + f * NcI + fc; 5464 if (hasPrec) { 5465 if (hasJac) elemMat[eOffset + i * totDim + i] = 1.0; 5466 elemMatP[eOffset + i * totDim + i] = 1.0; 5467 } else { 5468 elemMat[eOffset + i * totDim + i] = 1.0; 5469 } 5470 } 5471 } 5472 } 5473 } 5474 /* No allocated space for FV stuff, so ignore the zero entries */ 5475 PetscCall(MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE)); 5476 } 5477 /* Insert values into matrix */ 5478 for (c = cStart; c < cEnd; ++c) { 5479 const PetscInt cell = cells ? cells[c] : c; 5480 const PetscInt cind = c - cStart; 5481 5482 /* Transform to global basis before insertion in Jacobian */ 5483 if (transform) PetscCall(DMPlexBasisTransformPointTensor_Internal(dm, tdm, tv, cell, PETSC_TRUE, totDim, &elemMat[cind * totDim * totDim])); 5484 if (hasPrec) { 5485 if (hasJac) { 5486 if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind * totDim * totDim])); 5487 PetscCall(DMPlexMatSetClosure(dm, section, globalSection, Jac, cell, &elemMat[cind * totDim * totDim], ADD_VALUES)); 5488 } 5489 if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatP[cind * totDim * totDim])); 5490 PetscCall(DMPlexMatSetClosure(dm, section, globalSection, JacP, cell, &elemMatP[cind * totDim * totDim], ADD_VALUES)); 5491 } else { 5492 if (hasJac) { 5493 if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind * totDim * totDim])); 5494 PetscCall(DMPlexMatSetClosure(dm, section, globalSection, JacP, cell, &elemMat[cind * totDim * totDim], ADD_VALUES)); 5495 } 5496 } 5497 } 5498 PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 5499 if (hasFV) PetscCall(MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_FALSE)); 5500 PetscCall(PetscFree5(u, u_t, elemMat, elemMatP, elemMatD)); 5501 if (dmAux) { 5502 PetscCall(PetscFree(a)); 5503 PetscCall(DMDestroy(&plex)); 5504 } 5505 /* Compute boundary integrals */ 5506 PetscCall(DMPlexComputeBdJacobian_Internal(dm, X, X_t, t, X_tShift, Jac, JacP, user)); 5507 /* Assemble matrix */ 5508 end : { 5509 PetscBool assOp = hasJac && hasPrec ? PETSC_TRUE : PETSC_FALSE, gassOp; 5510 5511 PetscCallMPI(MPI_Allreduce(&assOp, &gassOp, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 5512 if (hasJac && hasPrec) { 5513 PetscCall(MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY)); 5514 PetscCall(MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY)); 5515 } 5516 } 5517 PetscCall(MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY)); 5518 PetscCall(MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY)); 5519 PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 5520 PetscFunctionReturn(PETSC_SUCCESS); 5521 } 5522 5523 PetscErrorCode DMPlexComputeJacobian_Hybrid_Internal(DM dm, PetscFormKey key[], IS cellIS, PetscReal t, PetscReal X_tShift, Vec locX, Vec locX_t, Mat Jac, Mat JacP, void *user) 5524 { 5525 DM_Plex *mesh = (DM_Plex *)dm->data; 5526 const char *name = "Hybrid Jacobian"; 5527 DM dmAux[3] = {NULL, NULL, NULL}; 5528 DMLabel ghostLabel = NULL; 5529 DM plex = NULL; 5530 DM plexA = NULL; 5531 PetscDS ds = NULL; 5532 PetscDS dsAux[3] = {NULL, NULL, NULL}; 5533 Vec locA[3] = {NULL, NULL, NULL}; 5534 PetscSection section = NULL; 5535 PetscSection sectionAux[3] = {NULL, NULL, NULL}; 5536 DMField coordField = NULL; 5537 PetscScalar *u = NULL, *u_t, *a[3]; 5538 PetscScalar *elemMat, *elemMatP; 5539 PetscSection globalSection; 5540 IS chunkIS; 5541 const PetscInt *cells; 5542 PetscInt *faces; 5543 PetscInt cStart, cEnd, numCells; 5544 PetscInt Nf, fieldI, fieldJ, totDim, totDimAux[3], numChunks, cellChunkSize, chunk; 5545 PetscInt maxDegree = PETSC_MAX_INT; 5546 PetscQuadrature affineQuad = NULL, *quads = NULL; 5547 PetscFEGeom *affineGeom = NULL, **geoms = NULL; 5548 PetscBool hasBdJac, hasBdPrec; 5549 5550 PetscFunctionBegin; 5551 if (!cellIS) PetscFunctionReturn(PETSC_SUCCESS); 5552 PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 5553 PetscCall(ISGetLocalSize(cellIS, &numCells)); 5554 if (cStart >= cEnd) PetscFunctionReturn(PETSC_SUCCESS); 5555 if ((key[0].label == key[1].label) && (key[0].value == key[1].value) && (key[0].part == key[1].part)) { 5556 const char *name; 5557 PetscCall(PetscObjectGetName((PetscObject)key[0].label, &name)); 5558 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Form keys for each side of a cohesive surface must be different (%s, %" PetscInt_FMT ", %" PetscInt_FMT ")", name, key[0].value, key[0].part); 5559 } 5560 PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 5561 PetscCall(DMConvert(dm, DMPLEX, &plex)); 5562 PetscCall(DMGetSection(dm, §ion)); 5563 PetscCall(DMGetGlobalSection(dm, &globalSection)); 5564 PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 5565 PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds)); 5566 PetscCall(PetscDSGetNumFields(ds, &Nf)); 5567 PetscCall(PetscDSGetTotalDimension(ds, &totDim)); 5568 PetscCall(PetscDSHasBdJacobian(ds, &hasBdJac)); 5569 PetscCall(PetscDSHasBdJacobianPreconditioner(ds, &hasBdPrec)); 5570 PetscCall(DMGetAuxiliaryVec(dm, key[2].label, key[2].value, key[2].part, &locA[2])); 5571 if (locA[2]) { 5572 const PetscInt cellStart = cells ? cells[cStart] : cStart; 5573 5574 PetscCall(VecGetDM(locA[2], &dmAux[2])); 5575 PetscCall(DMConvert(dmAux[2], DMPLEX, &plexA)); 5576 PetscCall(DMGetSection(dmAux[2], §ionAux[2])); 5577 PetscCall(DMGetCellDS(dmAux[2], cellStart, &dsAux[2])); 5578 PetscCall(PetscDSGetTotalDimension(dsAux[2], &totDimAux[2])); 5579 { 5580 const PetscInt *cone; 5581 PetscInt c; 5582 5583 PetscCall(DMPlexGetCone(dm, cellStart, &cone)); 5584 for (c = 0; c < 2; ++c) { 5585 const PetscInt *support; 5586 PetscInt ssize, s; 5587 5588 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 5589 PetscCall(DMPlexGetSupportSize(dm, cone[c], &ssize)); 5590 PetscCheck(ssize == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " from cell %" PetscInt_FMT " has support size %" PetscInt_FMT " != 2", cone[c], cellStart, ssize); 5591 if (support[0] == cellStart) s = 1; 5592 else if (support[1] == cellStart) s = 0; 5593 else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " does not have cell %" PetscInt_FMT " in its support", cone[c], cellStart); 5594 PetscCall(DMGetAuxiliaryVec(dm, key[c].label, key[c].value, key[c].part, &locA[c])); 5595 if (locA[c]) PetscCall(VecGetDM(locA[c], &dmAux[c])); 5596 else dmAux[c] = dmAux[2]; 5597 PetscCall(DMGetCellDS(dmAux[c], support[s], &dsAux[c])); 5598 PetscCall(PetscDSGetTotalDimension(dsAux[c], &totDimAux[c])); 5599 } 5600 } 5601 } 5602 PetscCall(DMGetCoordinateField(dm, &coordField)); 5603 PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 5604 if (maxDegree > 1) { 5605 PetscInt f; 5606 PetscCall(PetscCalloc2(Nf, &quads, Nf, &geoms)); 5607 for (f = 0; f < Nf; ++f) { 5608 PetscFE fe; 5609 5610 PetscCall(PetscDSGetDiscretization(ds, f, (PetscObject *)&fe)); 5611 if (fe) { 5612 PetscCall(PetscFEGetQuadrature(fe, &quads[f])); 5613 PetscCall(PetscObjectReference((PetscObject)quads[f])); 5614 } 5615 } 5616 } 5617 cellChunkSize = numCells; 5618 numChunks = !numCells ? 0 : PetscCeilReal(((PetscReal)numCells) / cellChunkSize); 5619 PetscCall(PetscCalloc1(1 * cellChunkSize, &faces)); 5620 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 1 * cellChunkSize, faces, PETSC_USE_POINTER, &chunkIS)); 5621 PetscCall(DMPlexGetCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2])); 5622 PetscCall(DMPlexGetHybridAuxFields(dm, dmAux, dsAux, cellIS, locA, a)); 5623 PetscCall(DMGetWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMat)); 5624 PetscCall(DMGetWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatP)); 5625 for (chunk = 0; chunk < numChunks; ++chunk) { 5626 PetscInt cS = cStart + chunk * cellChunkSize, cE = PetscMin(cS + cellChunkSize, cEnd), numCells = cE - cS, c; 5627 5628 if (hasBdJac) PetscCall(PetscMemzero(elemMat, numCells * totDim * totDim * sizeof(PetscScalar))); 5629 if (hasBdPrec) PetscCall(PetscMemzero(elemMatP, numCells * totDim * totDim * sizeof(PetscScalar))); 5630 /* Get faces */ 5631 for (c = cS; c < cE; ++c) { 5632 const PetscInt cell = cells ? cells[c] : c; 5633 const PetscInt *cone; 5634 PetscCall(DMPlexGetCone(plex, cell, &cone)); 5635 faces[0 * cellChunkSize + (c - cS)] = cone[0]; 5636 /*faces[2*cellChunkSize+(c-cS)] = cone[1];*/ 5637 } 5638 PetscCall(ISGeneralSetIndices(chunkIS, 1 * cellChunkSize, faces, PETSC_USE_POINTER)); 5639 if (maxDegree <= 1) { 5640 if (!affineQuad) PetscCall(DMFieldCreateDefaultQuadrature(coordField, chunkIS, &affineQuad)); 5641 if (affineQuad) PetscCall(DMSNESGetFEGeom(coordField, chunkIS, affineQuad, PETSC_TRUE, &affineGeom)); 5642 } else { 5643 PetscInt f; 5644 for (f = 0; f < Nf; ++f) { 5645 if (quads[f]) PetscCall(DMSNESGetFEGeom(coordField, chunkIS, quads[f], PETSC_TRUE, &geoms[f])); 5646 } 5647 } 5648 5649 for (fieldI = 0; fieldI < Nf; ++fieldI) { 5650 PetscFE feI; 5651 PetscFEGeom *geom = affineGeom ? affineGeom : geoms[fieldI]; 5652 PetscFEGeom *chunkGeom = NULL, *remGeom = NULL; 5653 PetscQuadrature quad = affineQuad ? affineQuad : quads[fieldI]; 5654 PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset, Nq, Nb; 5655 PetscBool isCohesiveField; 5656 5657 PetscCall(PetscDSGetDiscretization(ds, fieldI, (PetscObject *)&feI)); 5658 if (!feI) continue; 5659 PetscCall(PetscFEGetTileSizes(feI, NULL, &numBlocks, NULL, &numBatches)); 5660 PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL)); 5661 PetscCall(PetscFEGetDimension(feI, &Nb)); 5662 blockSize = Nb; 5663 batchSize = numBlocks * blockSize; 5664 PetscCall(PetscFESetTileSizes(feI, blockSize, numBlocks, batchSize, numBatches)); 5665 numChunks = numCells / (numBatches * batchSize); 5666 Ne = numChunks * numBatches * batchSize; 5667 Nr = numCells % (numBatches * batchSize); 5668 offset = numCells - Nr; 5669 PetscCall(PetscFEGeomGetChunk(geom, 0, offset, &chunkGeom)); 5670 PetscCall(PetscFEGeomGetChunk(geom, offset, numCells, &remGeom)); 5671 PetscCall(PetscDSGetCohesive(ds, fieldI, &isCohesiveField)); 5672 for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 5673 PetscFE feJ; 5674 5675 PetscCall(PetscDSGetDiscretization(ds, fieldJ, (PetscObject *)&feJ)); 5676 if (!feJ) continue; 5677 key[0].field = fieldI * Nf + fieldJ; 5678 key[1].field = fieldI * Nf + fieldJ; 5679 key[2].field = fieldI * Nf + fieldJ; 5680 if (hasBdJac) { 5681 PetscCall(PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN, key[0], 0, Ne, chunkGeom, u, u_t, dsAux[0], a[0], t, X_tShift, elemMat)); 5682 PetscCall(PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN, key[0], 0, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, dsAux[0], &a[0][offset * totDimAux[0]], t, X_tShift, &elemMat[offset * totDim * totDim])); 5683 PetscCall(PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN, key[1], 1, Ne, chunkGeom, u, u_t, dsAux[1], a[1], t, X_tShift, elemMat)); 5684 PetscCall(PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN, key[1], 1, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, dsAux[1], &a[1][offset * totDimAux[1]], t, X_tShift, &elemMat[offset * totDim * totDim])); 5685 } 5686 if (hasBdPrec) { 5687 PetscCall(PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN_PRE, key[0], 0, Ne, chunkGeom, u, u_t, dsAux[0], a[0], t, X_tShift, elemMatP)); 5688 PetscCall(PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN_PRE, key[0], 0, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, dsAux[0], &a[0][offset * totDimAux[0]], t, X_tShift, &elemMatP[offset * totDim * totDim])); 5689 PetscCall(PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN_PRE, key[1], 1, Ne, chunkGeom, u, u_t, dsAux[1], a[1], t, X_tShift, elemMatP)); 5690 PetscCall(PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN_PRE, key[1], 1, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, dsAux[1], &a[1][offset * totDimAux[1]], t, X_tShift, &elemMatP[offset * totDim * totDim])); 5691 } 5692 if (hasBdJac) { 5693 PetscCall(PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN, key[2], 2, Ne, chunkGeom, u, u_t, dsAux[2], a[2], t, X_tShift, elemMat)); 5694 PetscCall(PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN, key[2], 2, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, dsAux[2], &a[2][offset * totDimAux[2]], t, X_tShift, &elemMat[offset * totDim * totDim])); 5695 } 5696 if (hasBdPrec) { 5697 PetscCall(PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN_PRE, key[2], 2, Ne, chunkGeom, u, u_t, dsAux[2], a[2], t, X_tShift, elemMatP)); 5698 PetscCall(PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN_PRE, key[2], 2, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, dsAux[2], &a[2][offset * totDimAux[2]], t, X_tShift, &elemMatP[offset * totDim * totDim])); 5699 } 5700 } 5701 PetscCall(PetscFEGeomRestoreChunk(geom, offset, numCells, &remGeom)); 5702 PetscCall(PetscFEGeomRestoreChunk(geom, 0, offset, &chunkGeom)); 5703 } 5704 /* Insert values into matrix */ 5705 for (c = cS; c < cE; ++c) { 5706 const PetscInt cell = cells ? cells[c] : c; 5707 const PetscInt cind = c - cS; 5708 5709 if (hasBdPrec) { 5710 if (hasBdJac) { 5711 if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind * totDim * totDim])); 5712 PetscCall(DMPlexMatSetClosure(plex, section, globalSection, Jac, cell, &elemMat[cind * totDim * totDim], ADD_VALUES)); 5713 } 5714 if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatP[cind * totDim * totDim])); 5715 PetscCall(DMPlexMatSetClosure(plex, section, globalSection, JacP, cell, &elemMatP[cind * totDim * totDim], ADD_VALUES)); 5716 } else if (hasBdJac) { 5717 if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind * totDim * totDim])); 5718 PetscCall(DMPlexMatSetClosure(plex, section, globalSection, JacP, cell, &elemMat[cind * totDim * totDim], ADD_VALUES)); 5719 } 5720 } 5721 } 5722 PetscCall(DMPlexRestoreCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2])); 5723 PetscCall(DMPlexRestoreHybridAuxFields(dmAux, dsAux, cellIS, locA, a)); 5724 PetscCall(DMRestoreWorkArray(dm, hasBdJac ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMat)); 5725 PetscCall(DMRestoreWorkArray(dm, hasBdPrec ? cellChunkSize * totDim * totDim : 0, MPIU_SCALAR, &elemMatP)); 5726 PetscCall(PetscFree(faces)); 5727 PetscCall(ISDestroy(&chunkIS)); 5728 PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 5729 if (maxDegree <= 1) { 5730 PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, affineQuad, PETSC_FALSE, &affineGeom)); 5731 PetscCall(PetscQuadratureDestroy(&affineQuad)); 5732 } else { 5733 PetscInt f; 5734 for (f = 0; f < Nf; ++f) { 5735 if (geoms) PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, quads[f], PETSC_FALSE, &geoms[f])); 5736 if (quads) PetscCall(PetscQuadratureDestroy(&quads[f])); 5737 } 5738 PetscCall(PetscFree2(quads, geoms)); 5739 } 5740 if (dmAux[2]) PetscCall(DMDestroy(&plexA)); 5741 PetscCall(DMDestroy(&plex)); 5742 PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 5743 PetscFunctionReturn(PETSC_SUCCESS); 5744 } 5745 5746 /* 5747 DMPlexComputeJacobian_Action_Internal - Form the local portion of the Jacobian action Z = J(X) Y at the local solution X using pointwise functions specified by the user. 5748 5749 Input Parameters: 5750 + dm - The mesh 5751 . key - The PetscWeakFormKey indcating where integration should happen 5752 . cellIS - The cells to integrate over 5753 . t - The time 5754 . X_tShift - The multiplier for the Jacobian with repsect to X_t 5755 . X - Local solution vector 5756 . X_t - Time-derivative of the local solution vector 5757 . Y - Local input vector 5758 - user - the user context 5759 5760 Output Parameter: 5761 . Z - Local output vector 5762 5763 Note: 5764 We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator, 5765 like a GPU, or vectorize on a multicore machine. 5766 */ 5767 PetscErrorCode DMPlexComputeJacobian_Action_Internal(DM dm, PetscFormKey key, IS cellIS, PetscReal t, PetscReal X_tShift, Vec X, Vec X_t, Vec Y, Vec Z, void *user) 5768 { 5769 DM_Plex *mesh = (DM_Plex *)dm->data; 5770 const char *name = "Jacobian"; 5771 DM dmAux = NULL, plex, plexAux = NULL; 5772 DMEnclosureType encAux; 5773 Vec A; 5774 DMField coordField; 5775 PetscDS prob, probAux = NULL; 5776 PetscQuadrature quad; 5777 PetscSection section, globalSection, sectionAux; 5778 PetscScalar *elemMat, *elemMatD, *u, *u_t, *a = NULL, *y, *z; 5779 const PetscInt *cells; 5780 PetscInt Nf, fieldI, fieldJ; 5781 PetscInt totDim, totDimAux = 0, cStart, cEnd, numCells, c; 5782 PetscBool hasDyn; 5783 5784 PetscFunctionBegin; 5785 PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 5786 PetscCall(DMConvert(dm, DMPLEX, &plex)); 5787 if (!cellIS) { 5788 PetscInt depth; 5789 5790 PetscCall(DMPlexGetDepth(plex, &depth)); 5791 PetscCall(DMGetStratumIS(plex, "dim", depth, &cellIS)); 5792 if (!cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, &cellIS)); 5793 } else { 5794 PetscCall(PetscObjectReference((PetscObject)cellIS)); 5795 } 5796 PetscCall(ISGetLocalSize(cellIS, &numCells)); 5797 PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 5798 PetscCall(DMGetLocalSection(dm, §ion)); 5799 PetscCall(DMGetGlobalSection(dm, &globalSection)); 5800 PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob)); 5801 PetscCall(PetscDSGetNumFields(prob, &Nf)); 5802 PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 5803 PetscCall(PetscDSHasDynamicJacobian(prob, &hasDyn)); 5804 hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE; 5805 PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &A)); 5806 if (A) { 5807 PetscCall(VecGetDM(A, &dmAux)); 5808 PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 5809 PetscCall(DMConvert(dmAux, DMPLEX, &plexAux)); 5810 PetscCall(DMGetLocalSection(plexAux, §ionAux)); 5811 PetscCall(DMGetDS(dmAux, &probAux)); 5812 PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 5813 } 5814 PetscCall(VecSet(Z, 0.0)); 5815 PetscCall(PetscMalloc6(numCells * totDim, &u, X_t ? numCells * totDim : 0, &u_t, numCells * totDim * totDim, &elemMat, hasDyn ? numCells * totDim * totDim : 0, &elemMatD, numCells * totDim, &y, totDim, &z)); 5816 if (dmAux) PetscCall(PetscMalloc1(numCells * totDimAux, &a)); 5817 PetscCall(DMGetCoordinateField(dm, &coordField)); 5818 for (c = cStart; c < cEnd; ++c) { 5819 const PetscInt cell = cells ? cells[c] : c; 5820 const PetscInt cind = c - cStart; 5821 PetscScalar *x = NULL, *x_t = NULL; 5822 PetscInt i; 5823 5824 PetscCall(DMPlexVecGetClosure(plex, section, X, cell, NULL, &x)); 5825 for (i = 0; i < totDim; ++i) u[cind * totDim + i] = x[i]; 5826 PetscCall(DMPlexVecRestoreClosure(plex, section, X, cell, NULL, &x)); 5827 if (X_t) { 5828 PetscCall(DMPlexVecGetClosure(plex, section, X_t, cell, NULL, &x_t)); 5829 for (i = 0; i < totDim; ++i) u_t[cind * totDim + i] = x_t[i]; 5830 PetscCall(DMPlexVecRestoreClosure(plex, section, X_t, cell, NULL, &x_t)); 5831 } 5832 if (dmAux) { 5833 PetscInt subcell; 5834 PetscCall(DMGetEnclosurePoint(dmAux, dm, encAux, cell, &subcell)); 5835 PetscCall(DMPlexVecGetClosure(plexAux, sectionAux, A, subcell, NULL, &x)); 5836 for (i = 0; i < totDimAux; ++i) a[cind * totDimAux + i] = x[i]; 5837 PetscCall(DMPlexVecRestoreClosure(plexAux, sectionAux, A, subcell, NULL, &x)); 5838 } 5839 PetscCall(DMPlexVecGetClosure(plex, section, Y, cell, NULL, &x)); 5840 for (i = 0; i < totDim; ++i) y[cind * totDim + i] = x[i]; 5841 PetscCall(DMPlexVecRestoreClosure(plex, section, Y, cell, NULL, &x)); 5842 } 5843 PetscCall(PetscArrayzero(elemMat, numCells * totDim * totDim)); 5844 if (hasDyn) PetscCall(PetscArrayzero(elemMatD, numCells * totDim * totDim)); 5845 for (fieldI = 0; fieldI < Nf; ++fieldI) { 5846 PetscFE fe; 5847 PetscInt Nb; 5848 /* Conforming batches */ 5849 PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize; 5850 /* Remainder */ 5851 PetscInt Nr, offset, Nq; 5852 PetscQuadrature qGeom = NULL; 5853 PetscInt maxDegree; 5854 PetscFEGeom *cgeomFEM, *chunkGeom = NULL, *remGeom = NULL; 5855 5856 PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *)&fe)); 5857 PetscCall(PetscFEGetQuadrature(fe, &quad)); 5858 PetscCall(PetscFEGetDimension(fe, &Nb)); 5859 PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 5860 PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 5861 if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &qGeom)); 5862 if (!qGeom) { 5863 PetscCall(PetscFEGetQuadrature(fe, &qGeom)); 5864 PetscCall(PetscObjectReference((PetscObject)qGeom)); 5865 } 5866 PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL)); 5867 PetscCall(DMSNESGetFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 5868 blockSize = Nb; 5869 batchSize = numBlocks * blockSize; 5870 PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 5871 numChunks = numCells / (numBatches * batchSize); 5872 Ne = numChunks * numBatches * batchSize; 5873 Nr = numCells % (numBatches * batchSize); 5874 offset = numCells - Nr; 5875 PetscCall(PetscFEGeomGetChunk(cgeomFEM, 0, offset, &chunkGeom)); 5876 PetscCall(PetscFEGeomGetChunk(cgeomFEM, offset, numCells, &remGeom)); 5877 for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 5878 key.field = fieldI * Nf + fieldJ; 5879 PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat)); 5880 PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, probAux, &a[offset * totDimAux], t, X_tShift, &elemMat[offset * totDim * totDim])); 5881 if (hasDyn) { 5882 PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatD)); 5883 PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Nr, remGeom, &u[offset * totDim], u_t ? &u_t[offset * totDim] : NULL, probAux, &a[offset * totDimAux], t, X_tShift, &elemMatD[offset * totDim * totDim])); 5884 } 5885 } 5886 PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, offset, numCells, &remGeom)); 5887 PetscCall(PetscFEGeomRestoreChunk(cgeomFEM, 0, offset, &chunkGeom)); 5888 PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 5889 PetscCall(PetscQuadratureDestroy(&qGeom)); 5890 } 5891 if (hasDyn) { 5892 for (c = 0; c < numCells * totDim * totDim; ++c) elemMat[c] += X_tShift * elemMatD[c]; 5893 } 5894 for (c = cStart; c < cEnd; ++c) { 5895 const PetscInt cell = cells ? cells[c] : c; 5896 const PetscInt cind = c - cStart; 5897 const PetscBLASInt M = totDim, one = 1; 5898 const PetscScalar a = 1.0, b = 0.0; 5899 5900 PetscCallBLAS("BLASgemv", BLASgemv_("N", &M, &M, &a, &elemMat[cind * totDim * totDim], &M, &y[cind * totDim], &one, &b, z, &one)); 5901 if (mesh->printFEM > 1) { 5902 PetscCall(DMPrintCellMatrix(c, name, totDim, totDim, &elemMat[cind * totDim * totDim])); 5903 PetscCall(DMPrintCellVector(c, "Y", totDim, &y[cind * totDim])); 5904 PetscCall(DMPrintCellVector(c, "Z", totDim, z)); 5905 } 5906 PetscCall(DMPlexVecSetClosure(dm, section, Z, cell, z, ADD_VALUES)); 5907 } 5908 PetscCall(PetscFree6(u, u_t, elemMat, elemMatD, y, z)); 5909 if (mesh->printFEM) { 5910 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)Z), "Z:\n")); 5911 PetscCall(VecView(Z, NULL)); 5912 } 5913 PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 5914 PetscCall(PetscFree(a)); 5915 PetscCall(ISDestroy(&cellIS)); 5916 PetscCall(DMDestroy(&plexAux)); 5917 PetscCall(DMDestroy(&plex)); 5918 PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM, dm, 0, 0, 0)); 5919 PetscFunctionReturn(PETSC_SUCCESS); 5920 } 5921