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