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