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