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