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