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