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