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 PetscCheck(!ornt[0],PETSC_COMM_SELF, PETSC_ERR_SUP, "Face %" PetscInt_FMT " in hybrid cell %" PetscInt_FMT " has orientation %" PetscInt_FMT " != 0", cone[0], cell, ornt[0]); 3431 for (s = 0; s < 2; ++s) { 3432 const PetscInt *support; 3433 PetscScalar *x = NULL, *al = a[s]; 3434 const PetscInt tdA = totDimAux[s]; 3435 PetscInt ssize, scell; 3436 PetscInt subface, Na, i; 3437 3438 PetscCall(DMPlexGetSupport(dm, cone[s], &support)); 3439 PetscCall(DMPlexGetSupportSize(dm, cone[s], &ssize)); 3440 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); 3441 if (support[0] == cell) scell = support[1]; 3442 else if (support[1] == cell) scell = support[0]; 3443 else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " does not have cell %" PetscInt_FMT " in its support", cone[s], cell); 3444 3445 PetscCall(DMGetEnclosurePoint(plexA[s], dm, encAux[s], scell, &subface)); 3446 PetscCall(DMPlexVecGetClosure(plexA[s], sectionAux[s], locA[s], subface, &Na, &x)); 3447 for (i = 0; i < Na; ++i) al[cind*tdA+i] = x[i]; 3448 PetscCall(DMPlexVecRestoreClosure(plexA[s], sectionAux[s], locA[s], subface, &Na, &x)); 3449 } 3450 } 3451 for (s = 0; s < 2; ++s) PetscCall(DMDestroy(&plexA[s])); 3452 PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 3453 PetscFunctionReturn(0); 3454 } 3455 3456 static PetscErrorCode DMPlexRestoreHybridAuxFields(DM dmAux[], PetscDS dsAux[], IS cellIS, Vec locA[], PetscScalar *a[]) 3457 { 3458 PetscFunctionBegin; 3459 if (!locA[0] || !locA[1]) PetscFunctionReturn(0); 3460 PetscCall(DMRestoreWorkArray(dmAux[0], 0, MPIU_SCALAR, &a[0])); 3461 PetscCall(DMRestoreWorkArray(dmAux[1], 0, MPIU_SCALAR, &a[1])); 3462 PetscFunctionReturn(0); 3463 } 3464 3465 /*@C 3466 DMPlexGetFaceFields - Retrieve the field values values for a chunk of faces 3467 3468 Input Parameters: 3469 + dm - The DM 3470 . fStart - The first face to include 3471 . fEnd - The first face to exclude 3472 . locX - A local vector with the solution fields 3473 . locX_t - A local vector with solution field time derivatives, or NULL 3474 . faceGeometry - A local vector with face geometry 3475 . cellGeometry - A local vector with cell geometry 3476 - locaGrad - A local vector with field gradients, or NULL 3477 3478 Output Parameters: 3479 + Nface - The number of faces with field values 3480 . uL - The field values at the left side of the face 3481 - uR - The field values at the right side of the face 3482 3483 Level: developer 3484 3485 .seealso: `DMPlexGetCellFields()` 3486 @*/ 3487 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) 3488 { 3489 DM dmFace, dmCell, dmGrad = NULL; 3490 PetscSection section; 3491 PetscDS prob; 3492 DMLabel ghostLabel; 3493 const PetscScalar *facegeom, *cellgeom, *x, *lgrad; 3494 PetscBool *isFE; 3495 PetscInt dim, Nf, f, Nc, numFaces = fEnd - fStart, iface, face; 3496 3497 PetscFunctionBegin; 3498 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3499 PetscValidHeaderSpecific(locX, VEC_CLASSID, 4); 3500 if (locX_t) {PetscValidHeaderSpecific(locX_t, VEC_CLASSID, 5);} 3501 PetscValidHeaderSpecific(faceGeometry, VEC_CLASSID, 6); 3502 PetscValidHeaderSpecific(cellGeometry, VEC_CLASSID, 7); 3503 if (locGrad) {PetscValidHeaderSpecific(locGrad, VEC_CLASSID, 8);} 3504 PetscValidPointer(uL, 10); 3505 PetscValidPointer(uR, 11); 3506 PetscCall(DMGetDimension(dm, &dim)); 3507 PetscCall(DMGetDS(dm, &prob)); 3508 PetscCall(DMGetLocalSection(dm, §ion)); 3509 PetscCall(PetscDSGetNumFields(prob, &Nf)); 3510 PetscCall(PetscDSGetTotalComponents(prob, &Nc)); 3511 PetscCall(PetscMalloc1(Nf, &isFE)); 3512 for (f = 0; f < Nf; ++f) { 3513 PetscObject obj; 3514 PetscClassId id; 3515 3516 PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 3517 PetscCall(PetscObjectGetClassId(obj, &id)); 3518 if (id == PETSCFE_CLASSID) {isFE[f] = PETSC_TRUE;} 3519 else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;} 3520 else {isFE[f] = PETSC_FALSE;} 3521 } 3522 PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 3523 PetscCall(VecGetArrayRead(locX, &x)); 3524 PetscCall(VecGetDM(faceGeometry, &dmFace)); 3525 PetscCall(VecGetArrayRead(faceGeometry, &facegeom)); 3526 PetscCall(VecGetDM(cellGeometry, &dmCell)); 3527 PetscCall(VecGetArrayRead(cellGeometry, &cellgeom)); 3528 if (locGrad) { 3529 PetscCall(VecGetDM(locGrad, &dmGrad)); 3530 PetscCall(VecGetArrayRead(locGrad, &lgrad)); 3531 } 3532 PetscCall(DMGetWorkArray(dm, numFaces*Nc, MPIU_SCALAR, uL)); 3533 PetscCall(DMGetWorkArray(dm, numFaces*Nc, MPIU_SCALAR, uR)); 3534 /* Right now just eat the extra work for FE (could make a cell loop) */ 3535 for (face = fStart, iface = 0; face < fEnd; ++face) { 3536 const PetscInt *cells; 3537 PetscFVFaceGeom *fg; 3538 PetscFVCellGeom *cgL, *cgR; 3539 PetscScalar *xL, *xR, *gL, *gR; 3540 PetscScalar *uLl = *uL, *uRl = *uR; 3541 PetscInt ghost, nsupp, nchild; 3542 3543 PetscCall(DMLabelGetValue(ghostLabel, face, &ghost)); 3544 PetscCall(DMPlexGetSupportSize(dm, face, &nsupp)); 3545 PetscCall(DMPlexGetTreeChildren(dm, face, &nchild, NULL)); 3546 if (ghost >= 0 || nsupp > 2 || nchild > 0) continue; 3547 PetscCall(DMPlexPointLocalRead(dmFace, face, facegeom, &fg)); 3548 PetscCall(DMPlexGetSupport(dm, face, &cells)); 3549 PetscCall(DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cgL)); 3550 PetscCall(DMPlexPointLocalRead(dmCell, cells[1], cellgeom, &cgR)); 3551 for (f = 0; f < Nf; ++f) { 3552 PetscInt off; 3553 3554 PetscCall(PetscDSGetComponentOffset(prob, f, &off)); 3555 if (isFE[f]) { 3556 const PetscInt *cone; 3557 PetscInt comp, coneSizeL, coneSizeR, faceLocL, faceLocR, ldof, rdof, d; 3558 3559 xL = xR = NULL; 3560 PetscCall(PetscSectionGetFieldComponents(section, f, &comp)); 3561 PetscCall(DMPlexVecGetClosure(dm, section, locX, cells[0], &ldof, (PetscScalar **) &xL)); 3562 PetscCall(DMPlexVecGetClosure(dm, section, locX, cells[1], &rdof, (PetscScalar **) &xR)); 3563 PetscCall(DMPlexGetCone(dm, cells[0], &cone)); 3564 PetscCall(DMPlexGetConeSize(dm, cells[0], &coneSizeL)); 3565 for (faceLocL = 0; faceLocL < coneSizeL; ++faceLocL) if (cone[faceLocL] == face) break; 3566 PetscCall(DMPlexGetCone(dm, cells[1], &cone)); 3567 PetscCall(DMPlexGetConeSize(dm, cells[1], &coneSizeR)); 3568 for (faceLocR = 0; faceLocR < coneSizeR; ++faceLocR) if (cone[faceLocR] == face) break; 3569 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]); 3570 /* Check that FEM field has values in the right cell (sometimes its an FV ghost cell) */ 3571 /* TODO: this is a hack that might not be right for nonconforming */ 3572 if (faceLocL < coneSizeL) { 3573 PetscCall(PetscFEEvaluateFaceFields_Internal(prob, f, faceLocL, xL, &uLl[iface*Nc+off])); 3574 if (rdof == ldof && faceLocR < coneSizeR) PetscCall(PetscFEEvaluateFaceFields_Internal(prob, f, faceLocR, xR, &uRl[iface*Nc+off])); 3575 else {for (d = 0; d < comp; ++d) uRl[iface*Nc+off+d] = uLl[iface*Nc+off+d];} 3576 } 3577 else { 3578 PetscCall(PetscFEEvaluateFaceFields_Internal(prob, f, faceLocR, xR, &uRl[iface*Nc+off])); 3579 PetscCall(PetscSectionGetFieldComponents(section, f, &comp)); 3580 for (d = 0; d < comp; ++d) uLl[iface*Nc+off+d] = uRl[iface*Nc+off+d]; 3581 } 3582 PetscCall(DMPlexVecRestoreClosure(dm, section, locX, cells[0], &ldof, (PetscScalar **) &xL)); 3583 PetscCall(DMPlexVecRestoreClosure(dm, section, locX, cells[1], &rdof, (PetscScalar **) &xR)); 3584 } else { 3585 PetscFV fv; 3586 PetscInt numComp, c; 3587 3588 PetscCall(PetscDSGetDiscretization(prob, f, (PetscObject *) &fv)); 3589 PetscCall(PetscFVGetNumComponents(fv, &numComp)); 3590 PetscCall(DMPlexPointLocalFieldRead(dm, cells[0], f, x, &xL)); 3591 PetscCall(DMPlexPointLocalFieldRead(dm, cells[1], f, x, &xR)); 3592 if (dmGrad) { 3593 PetscReal dxL[3], dxR[3]; 3594 3595 PetscCall(DMPlexPointLocalRead(dmGrad, cells[0], lgrad, &gL)); 3596 PetscCall(DMPlexPointLocalRead(dmGrad, cells[1], lgrad, &gR)); 3597 DMPlex_WaxpyD_Internal(dim, -1, cgL->centroid, fg->centroid, dxL); 3598 DMPlex_WaxpyD_Internal(dim, -1, cgR->centroid, fg->centroid, dxR); 3599 for (c = 0; c < numComp; ++c) { 3600 uLl[iface*Nc+off+c] = xL[c] + DMPlex_DotD_Internal(dim, &gL[c*dim], dxL); 3601 uRl[iface*Nc+off+c] = xR[c] + DMPlex_DotD_Internal(dim, &gR[c*dim], dxR); 3602 } 3603 } else { 3604 for (c = 0; c < numComp; ++c) { 3605 uLl[iface*Nc+off+c] = xL[c]; 3606 uRl[iface*Nc+off+c] = xR[c]; 3607 } 3608 } 3609 } 3610 } 3611 ++iface; 3612 } 3613 *Nface = iface; 3614 PetscCall(VecRestoreArrayRead(locX, &x)); 3615 PetscCall(VecRestoreArrayRead(faceGeometry, &facegeom)); 3616 PetscCall(VecRestoreArrayRead(cellGeometry, &cellgeom)); 3617 if (locGrad) { 3618 PetscCall(VecRestoreArrayRead(locGrad, &lgrad)); 3619 } 3620 PetscCall(PetscFree(isFE)); 3621 PetscFunctionReturn(0); 3622 } 3623 3624 /*@C 3625 DMPlexRestoreFaceFields - Restore the field values values for a chunk of faces 3626 3627 Input Parameters: 3628 + dm - The DM 3629 . fStart - The first face to include 3630 . fEnd - The first face to exclude 3631 . locX - A local vector with the solution fields 3632 . locX_t - A local vector with solution field time derivatives, or NULL 3633 . faceGeometry - A local vector with face geometry 3634 . cellGeometry - A local vector with cell geometry 3635 - locaGrad - A local vector with field gradients, or NULL 3636 3637 Output Parameters: 3638 + Nface - The number of faces with field values 3639 . uL - The field values at the left side of the face 3640 - uR - The field values at the right side of the face 3641 3642 Level: developer 3643 3644 .seealso: `DMPlexGetFaceFields()` 3645 @*/ 3646 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) 3647 { 3648 PetscFunctionBegin; 3649 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, uL)); 3650 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, uR)); 3651 PetscFunctionReturn(0); 3652 } 3653 3654 /*@C 3655 DMPlexGetFaceGeometry - Retrieve the geometric values for a chunk of faces 3656 3657 Input Parameters: 3658 + dm - The DM 3659 . fStart - The first face to include 3660 . fEnd - The first face to exclude 3661 . faceGeometry - A local vector with face geometry 3662 - cellGeometry - A local vector with cell geometry 3663 3664 Output Parameters: 3665 + Nface - The number of faces with field values 3666 . fgeom - The extract the face centroid and normal 3667 - vol - The cell volume 3668 3669 Level: developer 3670 3671 .seealso: `DMPlexGetCellFields()` 3672 @*/ 3673 PetscErrorCode DMPlexGetFaceGeometry(DM dm, PetscInt fStart, PetscInt fEnd, Vec faceGeometry, Vec cellGeometry, PetscInt *Nface, PetscFVFaceGeom **fgeom, PetscReal **vol) 3674 { 3675 DM dmFace, dmCell; 3676 DMLabel ghostLabel; 3677 const PetscScalar *facegeom, *cellgeom; 3678 PetscInt dim, numFaces = fEnd - fStart, iface, face; 3679 3680 PetscFunctionBegin; 3681 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3682 PetscValidHeaderSpecific(faceGeometry, VEC_CLASSID, 4); 3683 PetscValidHeaderSpecific(cellGeometry, VEC_CLASSID, 5); 3684 PetscValidPointer(fgeom, 7); 3685 PetscValidPointer(vol, 8); 3686 PetscCall(DMGetDimension(dm, &dim)); 3687 PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 3688 PetscCall(VecGetDM(faceGeometry, &dmFace)); 3689 PetscCall(VecGetArrayRead(faceGeometry, &facegeom)); 3690 PetscCall(VecGetDM(cellGeometry, &dmCell)); 3691 PetscCall(VecGetArrayRead(cellGeometry, &cellgeom)); 3692 PetscCall(PetscMalloc1(numFaces, fgeom)); 3693 PetscCall(DMGetWorkArray(dm, numFaces*2, MPIU_SCALAR, vol)); 3694 for (face = fStart, iface = 0; face < fEnd; ++face) { 3695 const PetscInt *cells; 3696 PetscFVFaceGeom *fg; 3697 PetscFVCellGeom *cgL, *cgR; 3698 PetscFVFaceGeom *fgeoml = *fgeom; 3699 PetscReal *voll = *vol; 3700 PetscInt ghost, d, nchild, nsupp; 3701 3702 PetscCall(DMLabelGetValue(ghostLabel, face, &ghost)); 3703 PetscCall(DMPlexGetSupportSize(dm, face, &nsupp)); 3704 PetscCall(DMPlexGetTreeChildren(dm, face, &nchild, NULL)); 3705 if (ghost >= 0 || nsupp > 2 || nchild > 0) continue; 3706 PetscCall(DMPlexPointLocalRead(dmFace, face, facegeom, &fg)); 3707 PetscCall(DMPlexGetSupport(dm, face, &cells)); 3708 PetscCall(DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cgL)); 3709 PetscCall(DMPlexPointLocalRead(dmCell, cells[1], cellgeom, &cgR)); 3710 for (d = 0; d < dim; ++d) { 3711 fgeoml[iface].centroid[d] = fg->centroid[d]; 3712 fgeoml[iface].normal[d] = fg->normal[d]; 3713 } 3714 voll[iface*2+0] = cgL->volume; 3715 voll[iface*2+1] = cgR->volume; 3716 ++iface; 3717 } 3718 *Nface = iface; 3719 PetscCall(VecRestoreArrayRead(faceGeometry, &facegeom)); 3720 PetscCall(VecRestoreArrayRead(cellGeometry, &cellgeom)); 3721 PetscFunctionReturn(0); 3722 } 3723 3724 /*@C 3725 DMPlexRestoreFaceGeometry - Restore the field values values for a chunk of faces 3726 3727 Input Parameters: 3728 + dm - The DM 3729 . fStart - The first face to include 3730 . fEnd - The first face to exclude 3731 . faceGeometry - A local vector with face geometry 3732 - cellGeometry - A local vector with cell geometry 3733 3734 Output Parameters: 3735 + Nface - The number of faces with field values 3736 . fgeom - The extract the face centroid and normal 3737 - vol - The cell volume 3738 3739 Level: developer 3740 3741 .seealso: `DMPlexGetFaceFields()` 3742 @*/ 3743 PetscErrorCode DMPlexRestoreFaceGeometry(DM dm, PetscInt fStart, PetscInt fEnd, Vec faceGeometry, Vec cellGeometry, PetscInt *Nface, PetscFVFaceGeom **fgeom, PetscReal **vol) 3744 { 3745 PetscFunctionBegin; 3746 PetscCall(PetscFree(*fgeom)); 3747 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_REAL, vol)); 3748 PetscFunctionReturn(0); 3749 } 3750 3751 PetscErrorCode DMSNESGetFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom) 3752 { 3753 char composeStr[33] = {0}; 3754 PetscObjectId id; 3755 PetscContainer container; 3756 3757 PetscFunctionBegin; 3758 PetscCall(PetscObjectGetId((PetscObject)quad,&id)); 3759 PetscCall(PetscSNPrintf(composeStr, 32, "DMSNESGetFEGeom_%" PetscInt64_FMT "\n", id)); 3760 PetscCall(PetscObjectQuery((PetscObject) pointIS, composeStr, (PetscObject *) &container)); 3761 if (container) { 3762 PetscCall(PetscContainerGetPointer(container, (void **) geom)); 3763 } else { 3764 PetscCall(DMFieldCreateFEGeom(coordField, pointIS, quad, faceData, geom)); 3765 PetscCall(PetscContainerCreate(PETSC_COMM_SELF,&container)); 3766 PetscCall(PetscContainerSetPointer(container, (void *) *geom)); 3767 PetscCall(PetscContainerSetUserDestroy(container, PetscContainerUserDestroy_PetscFEGeom)); 3768 PetscCall(PetscObjectCompose((PetscObject) pointIS, composeStr, (PetscObject) container)); 3769 PetscCall(PetscContainerDestroy(&container)); 3770 } 3771 PetscFunctionReturn(0); 3772 } 3773 3774 PetscErrorCode DMSNESRestoreFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom) 3775 { 3776 PetscFunctionBegin; 3777 *geom = NULL; 3778 PetscFunctionReturn(0); 3779 } 3780 3781 PetscErrorCode DMPlexComputeResidual_Patch_Internal(DM dm, PetscSection section, IS cellIS, PetscReal t, Vec locX, Vec locX_t, Vec locF, void *user) 3782 { 3783 DM_Plex *mesh = (DM_Plex *) dm->data; 3784 const char *name = "Residual"; 3785 DM dmAux = NULL; 3786 DMLabel ghostLabel = NULL; 3787 PetscDS prob = NULL; 3788 PetscDS probAux = NULL; 3789 PetscBool useFEM = PETSC_FALSE; 3790 PetscBool isImplicit = (locX_t || t == PETSC_MIN_REAL) ? PETSC_TRUE : PETSC_FALSE; 3791 DMField coordField = NULL; 3792 Vec locA; 3793 PetscScalar *u = NULL, *u_t, *a, *uL = NULL, *uR = NULL; 3794 IS chunkIS; 3795 const PetscInt *cells; 3796 PetscInt cStart, cEnd, numCells; 3797 PetscInt Nf, f, totDim, totDimAux, numChunks, cellChunkSize, chunk, fStart, fEnd; 3798 PetscInt maxDegree = PETSC_MAX_INT; 3799 PetscFormKey key; 3800 PetscQuadrature affineQuad = NULL, *quads = NULL; 3801 PetscFEGeom *affineGeom = NULL, **geoms = NULL; 3802 3803 PetscFunctionBegin; 3804 PetscCall(PetscLogEventBegin(DMPLEX_ResidualFEM,dm,0,0,0)); 3805 /* FEM+FVM */ 3806 /* 1: Get sizes from dm and dmAux */ 3807 PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 3808 PetscCall(DMGetDS(dm, &prob)); 3809 PetscCall(PetscDSGetNumFields(prob, &Nf)); 3810 PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 3811 PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &locA)); 3812 if (locA) { 3813 PetscCall(VecGetDM(locA, &dmAux)); 3814 PetscCall(DMGetDS(dmAux, &probAux)); 3815 PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 3816 } 3817 /* 2: Get geometric data */ 3818 for (f = 0; f < Nf; ++f) { 3819 PetscObject obj; 3820 PetscClassId id; 3821 PetscBool fimp; 3822 3823 PetscCall(PetscDSGetImplicit(prob, f, &fimp)); 3824 if (isImplicit != fimp) continue; 3825 PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 3826 PetscCall(PetscObjectGetClassId(obj, &id)); 3827 if (id == PETSCFE_CLASSID) {useFEM = PETSC_TRUE;} 3828 PetscCheck(id != PETSCFV_CLASSID,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Use of FVM with PCPATCH not yet implemented"); 3829 } 3830 if (useFEM) { 3831 PetscCall(DMGetCoordinateField(dm, &coordField)); 3832 PetscCall(DMFieldGetDegree(coordField,cellIS,NULL,&maxDegree)); 3833 if (maxDegree <= 1) { 3834 PetscCall(DMFieldCreateDefaultQuadrature(coordField,cellIS,&affineQuad)); 3835 if (affineQuad) { 3836 PetscCall(DMSNESGetFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom)); 3837 } 3838 } else { 3839 PetscCall(PetscCalloc2(Nf,&quads,Nf,&geoms)); 3840 for (f = 0; f < Nf; ++f) { 3841 PetscObject obj; 3842 PetscClassId id; 3843 PetscBool fimp; 3844 3845 PetscCall(PetscDSGetImplicit(prob, f, &fimp)); 3846 if (isImplicit != fimp) continue; 3847 PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 3848 PetscCall(PetscObjectGetClassId(obj, &id)); 3849 if (id == PETSCFE_CLASSID) { 3850 PetscFE fe = (PetscFE) obj; 3851 3852 PetscCall(PetscFEGetQuadrature(fe, &quads[f])); 3853 PetscCall(PetscObjectReference((PetscObject)quads[f])); 3854 PetscCall(DMSNESGetFEGeom(coordField,cellIS,quads[f],PETSC_FALSE,&geoms[f])); 3855 } 3856 } 3857 } 3858 } 3859 /* Loop over chunks */ 3860 PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 3861 PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 3862 if (useFEM) PetscCall(ISCreate(PETSC_COMM_SELF, &chunkIS)); 3863 numCells = cEnd - cStart; 3864 numChunks = 1; 3865 cellChunkSize = numCells/numChunks; 3866 numChunks = PetscMin(1,numCells); 3867 key.label = NULL; 3868 key.value = 0; 3869 key.part = 0; 3870 for (chunk = 0; chunk < numChunks; ++chunk) { 3871 PetscScalar *elemVec, *fluxL = NULL, *fluxR = NULL; 3872 PetscReal *vol = NULL; 3873 PetscFVFaceGeom *fgeom = NULL; 3874 PetscInt cS = cStart+chunk*cellChunkSize, cE = PetscMin(cS+cellChunkSize, cEnd), numCells = cE - cS, c; 3875 PetscInt numFaces = 0; 3876 3877 /* Extract field coefficients */ 3878 if (useFEM) { 3879 PetscCall(ISGetPointSubrange(chunkIS, cS, cE, cells)); 3880 PetscCall(DMPlexGetCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a)); 3881 PetscCall(DMGetWorkArray(dm, numCells*totDim, MPIU_SCALAR, &elemVec)); 3882 PetscCall(PetscArrayzero(elemVec, numCells*totDim)); 3883 } 3884 /* TODO We will interlace both our field coefficients (u, u_t, uL, uR, etc.) and our output (elemVec, fL, fR). I think this works */ 3885 /* Loop over fields */ 3886 for (f = 0; f < Nf; ++f) { 3887 PetscObject obj; 3888 PetscClassId id; 3889 PetscBool fimp; 3890 PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset; 3891 3892 key.field = f; 3893 PetscCall(PetscDSGetImplicit(prob, f, &fimp)); 3894 if (isImplicit != fimp) continue; 3895 PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 3896 PetscCall(PetscObjectGetClassId(obj, &id)); 3897 if (id == PETSCFE_CLASSID) { 3898 PetscFE fe = (PetscFE) obj; 3899 PetscFEGeom *geom = affineGeom ? affineGeom : geoms[f]; 3900 PetscFEGeom *chunkGeom = NULL; 3901 PetscQuadrature quad = affineQuad ? affineQuad : quads[f]; 3902 PetscInt Nq, Nb; 3903 3904 PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 3905 PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL)); 3906 PetscCall(PetscFEGetDimension(fe, &Nb)); 3907 blockSize = Nb; 3908 batchSize = numBlocks * blockSize; 3909 PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 3910 numChunks = numCells / (numBatches*batchSize); 3911 Ne = numChunks*numBatches*batchSize; 3912 Nr = numCells % (numBatches*batchSize); 3913 offset = numCells - Nr; 3914 /* Integrate FE residual to get elemVec (need fields at quadrature points) */ 3915 /* 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) */ 3916 PetscCall(PetscFEGeomGetChunk(geom,0,offset,&chunkGeom)); 3917 PetscCall(PetscFEIntegrateResidual(prob, key, Ne, chunkGeom, u, u_t, probAux, a, t, elemVec)); 3918 PetscCall(PetscFEGeomGetChunk(geom,offset,numCells,&chunkGeom)); 3919 PetscCall(PetscFEIntegrateResidual(prob, key, Nr, chunkGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, probAux, &a[offset*totDimAux], t, &elemVec[offset*totDim])); 3920 PetscCall(PetscFEGeomRestoreChunk(geom,offset,numCells,&chunkGeom)); 3921 } else if (id == PETSCFV_CLASSID) { 3922 PetscFV fv = (PetscFV) obj; 3923 3924 Ne = numFaces; 3925 /* Riemann solve over faces (need fields at face centroids) */ 3926 /* We need to evaluate FE fields at those coordinates */ 3927 PetscCall(PetscFVIntegrateRHSFunction(fv, prob, f, Ne, fgeom, vol, uL, uR, fluxL, fluxR)); 3928 } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f); 3929 } 3930 /* Loop over domain */ 3931 if (useFEM) { 3932 /* Add elemVec to locX */ 3933 for (c = cS; c < cE; ++c) { 3934 const PetscInt cell = cells ? cells[c] : c; 3935 const PetscInt cind = c - cStart; 3936 3937 if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, name, totDim, &elemVec[cind*totDim])); 3938 if (ghostLabel) { 3939 PetscInt ghostVal; 3940 3941 PetscCall(DMLabelGetValue(ghostLabel,cell,&ghostVal)); 3942 if (ghostVal > 0) continue; 3943 } 3944 PetscCall(DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind*totDim], ADD_ALL_VALUES)); 3945 } 3946 } 3947 /* Handle time derivative */ 3948 if (locX_t) { 3949 PetscScalar *x_t, *fa; 3950 3951 PetscCall(VecGetArray(locF, &fa)); 3952 PetscCall(VecGetArray(locX_t, &x_t)); 3953 for (f = 0; f < Nf; ++f) { 3954 PetscFV fv; 3955 PetscObject obj; 3956 PetscClassId id; 3957 PetscInt pdim, d; 3958 3959 PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 3960 PetscCall(PetscObjectGetClassId(obj, &id)); 3961 if (id != PETSCFV_CLASSID) continue; 3962 fv = (PetscFV) obj; 3963 PetscCall(PetscFVGetNumComponents(fv, &pdim)); 3964 for (c = cS; c < cE; ++c) { 3965 const PetscInt cell = cells ? cells[c] : c; 3966 PetscScalar *u_t, *r; 3967 3968 if (ghostLabel) { 3969 PetscInt ghostVal; 3970 3971 PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal)); 3972 if (ghostVal > 0) continue; 3973 } 3974 PetscCall(DMPlexPointLocalFieldRead(dm, cell, f, x_t, &u_t)); 3975 PetscCall(DMPlexPointLocalFieldRef(dm, cell, f, fa, &r)); 3976 for (d = 0; d < pdim; ++d) r[d] += u_t[d]; 3977 } 3978 } 3979 PetscCall(VecRestoreArray(locX_t, &x_t)); 3980 PetscCall(VecRestoreArray(locF, &fa)); 3981 } 3982 if (useFEM) { 3983 PetscCall(DMPlexRestoreCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a)); 3984 PetscCall(DMRestoreWorkArray(dm, numCells*totDim, MPIU_SCALAR, &elemVec)); 3985 } 3986 } 3987 if (useFEM) PetscCall(ISDestroy(&chunkIS)); 3988 PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 3989 /* TODO Could include boundary residual here (see DMPlexComputeResidual_Internal) */ 3990 if (useFEM) { 3991 if (maxDegree <= 1) { 3992 PetscCall(DMSNESRestoreFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom)); 3993 PetscCall(PetscQuadratureDestroy(&affineQuad)); 3994 } else { 3995 for (f = 0; f < Nf; ++f) { 3996 PetscCall(DMSNESRestoreFEGeom(coordField,cellIS,quads[f],PETSC_FALSE,&geoms[f])); 3997 PetscCall(PetscQuadratureDestroy(&quads[f])); 3998 } 3999 PetscCall(PetscFree2(quads,geoms)); 4000 } 4001 } 4002 PetscCall(PetscLogEventEnd(DMPLEX_ResidualFEM,dm,0,0,0)); 4003 PetscFunctionReturn(0); 4004 } 4005 4006 /* 4007 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 4008 4009 X - The local solution vector 4010 X_t - The local solution time derivative vector, or NULL 4011 */ 4012 PetscErrorCode DMPlexComputeJacobian_Patch_Internal(DM dm, PetscSection section, PetscSection globalSection, IS cellIS, 4013 PetscReal t, PetscReal X_tShift, Vec X, Vec X_t, Mat Jac, Mat JacP, void *ctx) 4014 { 4015 DM_Plex *mesh = (DM_Plex *) dm->data; 4016 const char *name = "Jacobian", *nameP = "JacobianPre"; 4017 DM dmAux = NULL; 4018 PetscDS prob, probAux = NULL; 4019 PetscSection sectionAux = NULL; 4020 Vec A; 4021 DMField coordField; 4022 PetscFEGeom *cgeomFEM; 4023 PetscQuadrature qGeom = NULL; 4024 Mat J = Jac, JP = JacP; 4025 PetscScalar *work, *u = NULL, *u_t = NULL, *a = NULL, *elemMat = NULL, *elemMatP = NULL, *elemMatD = NULL; 4026 PetscBool hasJac, hasPrec, hasDyn, assembleJac, *isFE, hasFV = PETSC_FALSE; 4027 const PetscInt *cells; 4028 PetscFormKey key; 4029 PetscInt Nf, fieldI, fieldJ, maxDegree, numCells, cStart, cEnd, numChunks, chunkSize, chunk, totDim, totDimAux = 0, sz, wsz, off = 0, offCell = 0; 4030 4031 PetscFunctionBegin; 4032 PetscCall(ISGetLocalSize(cellIS, &numCells)); 4033 PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 4034 PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM,dm,0,0,0)); 4035 PetscCall(DMGetDS(dm, &prob)); 4036 PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &A)); 4037 if (A) { 4038 PetscCall(VecGetDM(A, &dmAux)); 4039 PetscCall(DMGetLocalSection(dmAux, §ionAux)); 4040 PetscCall(DMGetDS(dmAux, &probAux)); 4041 } 4042 /* Get flags */ 4043 PetscCall(PetscDSGetNumFields(prob, &Nf)); 4044 PetscCall(DMGetWorkArray(dm, Nf, MPIU_BOOL, &isFE)); 4045 for (fieldI = 0; fieldI < Nf; ++fieldI) { 4046 PetscObject disc; 4047 PetscClassId id; 4048 PetscCall(PetscDSGetDiscretization(prob, fieldI, &disc)); 4049 PetscCall(PetscObjectGetClassId(disc, &id)); 4050 if (id == PETSCFE_CLASSID) {isFE[fieldI] = PETSC_TRUE;} 4051 else if (id == PETSCFV_CLASSID) {hasFV = PETSC_TRUE; isFE[fieldI] = PETSC_FALSE;} 4052 } 4053 PetscCall(PetscDSHasJacobian(prob, &hasJac)); 4054 PetscCall(PetscDSHasJacobianPreconditioner(prob, &hasPrec)); 4055 PetscCall(PetscDSHasDynamicJacobian(prob, &hasDyn)); 4056 assembleJac = hasJac && hasPrec && (Jac != JacP) ? PETSC_TRUE : PETSC_FALSE; 4057 hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE; 4058 if (hasFV) PetscCall(MatSetOption(JP, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE)); /* No allocated space for FV stuff, so ignore the zero entries */ 4059 PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 4060 if (probAux) PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 4061 /* Compute batch sizes */ 4062 if (isFE[0]) { 4063 PetscFE fe; 4064 PetscQuadrature q; 4065 PetscInt numQuadPoints, numBatches, batchSize, numBlocks, blockSize, Nb; 4066 4067 PetscCall(PetscDSGetDiscretization(prob, 0, (PetscObject *) &fe)); 4068 PetscCall(PetscFEGetQuadrature(fe, &q)); 4069 PetscCall(PetscQuadratureGetData(q, NULL, NULL, &numQuadPoints, NULL, NULL)); 4070 PetscCall(PetscFEGetDimension(fe, &Nb)); 4071 PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 4072 blockSize = Nb*numQuadPoints; 4073 batchSize = numBlocks * blockSize; 4074 chunkSize = numBatches * batchSize; 4075 numChunks = numCells / chunkSize + numCells % chunkSize; 4076 PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 4077 } else { 4078 chunkSize = numCells; 4079 numChunks = 1; 4080 } 4081 /* Get work space */ 4082 wsz = (((X?1:0) + (X_t?1:0) + (dmAux?1:0))*totDim + ((hasJac?1:0) + (hasPrec?1:0) + (hasDyn?1:0))*totDim*totDim)*chunkSize; 4083 PetscCall(DMGetWorkArray(dm, wsz, MPIU_SCALAR, &work)); 4084 PetscCall(PetscArrayzero(work, wsz)); 4085 off = 0; 4086 u = X ? (sz = chunkSize*totDim, off += sz, work+off-sz) : NULL; 4087 u_t = X_t ? (sz = chunkSize*totDim, off += sz, work+off-sz) : NULL; 4088 a = dmAux ? (sz = chunkSize*totDimAux, off += sz, work+off-sz) : NULL; 4089 elemMat = hasJac ? (sz = chunkSize*totDim*totDim, off += sz, work+off-sz) : NULL; 4090 elemMatP = hasPrec ? (sz = chunkSize*totDim*totDim, off += sz, work+off-sz) : NULL; 4091 elemMatD = hasDyn ? (sz = chunkSize*totDim*totDim, off += sz, work+off-sz) : NULL; 4092 PetscCheck(off == wsz,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Error is workspace size %" PetscInt_FMT " should be %" PetscInt_FMT, off, wsz); 4093 /* Setup geometry */ 4094 PetscCall(DMGetCoordinateField(dm, &coordField)); 4095 PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 4096 if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &qGeom)); 4097 if (!qGeom) { 4098 PetscFE fe; 4099 4100 PetscCall(PetscDSGetDiscretization(prob, 0, (PetscObject *) &fe)); 4101 PetscCall(PetscFEGetQuadrature(fe, &qGeom)); 4102 PetscCall(PetscObjectReference((PetscObject) qGeom)); 4103 } 4104 PetscCall(DMSNESGetFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 4105 /* Compute volume integrals */ 4106 if (assembleJac) PetscCall(MatZeroEntries(J)); 4107 PetscCall(MatZeroEntries(JP)); 4108 key.label = NULL; 4109 key.value = 0; 4110 key.part = 0; 4111 for (chunk = 0; chunk < numChunks; ++chunk, offCell += chunkSize) { 4112 const PetscInt Ncell = PetscMin(chunkSize, numCells - offCell); 4113 PetscInt c; 4114 4115 /* Extract values */ 4116 for (c = 0; c < Ncell; ++c) { 4117 const PetscInt cell = cells ? cells[c+offCell] : c+offCell; 4118 PetscScalar *x = NULL, *x_t = NULL; 4119 PetscInt i; 4120 4121 if (X) { 4122 PetscCall(DMPlexVecGetClosure(dm, section, X, cell, NULL, &x)); 4123 for (i = 0; i < totDim; ++i) u[c*totDim+i] = x[i]; 4124 PetscCall(DMPlexVecRestoreClosure(dm, section, X, cell, NULL, &x)); 4125 } 4126 if (X_t) { 4127 PetscCall(DMPlexVecGetClosure(dm, section, X_t, cell, NULL, &x_t)); 4128 for (i = 0; i < totDim; ++i) u_t[c*totDim+i] = x_t[i]; 4129 PetscCall(DMPlexVecRestoreClosure(dm, section, X_t, cell, NULL, &x_t)); 4130 } 4131 if (dmAux) { 4132 PetscCall(DMPlexVecGetClosure(dmAux, sectionAux, A, cell, NULL, &x)); 4133 for (i = 0; i < totDimAux; ++i) a[c*totDimAux+i] = x[i]; 4134 PetscCall(DMPlexVecRestoreClosure(dmAux, sectionAux, A, cell, NULL, &x)); 4135 } 4136 } 4137 for (fieldI = 0; fieldI < Nf; ++fieldI) { 4138 PetscFE fe; 4139 PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fe)); 4140 for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 4141 key.field = fieldI*Nf + fieldJ; 4142 if (hasJac) PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMat)); 4143 if (hasPrec) PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, key, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMatP)); 4144 if (hasDyn) PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMatD)); 4145 } 4146 /* For finite volume, add the identity */ 4147 if (!isFE[fieldI]) { 4148 PetscFV fv; 4149 PetscInt eOffset = 0, Nc, fc, foff; 4150 4151 PetscCall(PetscDSGetFieldOffset(prob, fieldI, &foff)); 4152 PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fv)); 4153 PetscCall(PetscFVGetNumComponents(fv, &Nc)); 4154 for (c = 0; c < chunkSize; ++c, eOffset += totDim*totDim) { 4155 for (fc = 0; fc < Nc; ++fc) { 4156 const PetscInt i = foff + fc; 4157 if (hasJac) {elemMat [eOffset+i*totDim+i] = 1.0;} 4158 if (hasPrec) {elemMatP[eOffset+i*totDim+i] = 1.0;} 4159 } 4160 } 4161 } 4162 } 4163 /* Add contribution from X_t */ 4164 if (hasDyn) {for (c = 0; c < chunkSize*totDim*totDim; ++c) elemMat[c] += X_tShift*elemMatD[c];} 4165 /* Insert values into matrix */ 4166 for (c = 0; c < Ncell; ++c) { 4167 const PetscInt cell = cells ? cells[c+offCell] : c+offCell; 4168 if (mesh->printFEM > 1) { 4169 if (hasJac) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[(c-cStart)*totDim*totDim])); 4170 if (hasPrec) PetscCall(DMPrintCellMatrix(cell, nameP, totDim, totDim, &elemMatP[(c-cStart)*totDim*totDim])); 4171 } 4172 if (assembleJac) PetscCall(DMPlexMatSetClosure(dm, section, globalSection, Jac, cell, &elemMat[(c-cStart)*totDim*totDim], ADD_VALUES)); 4173 PetscCall(DMPlexMatSetClosure(dm, section, globalSection, JP, cell, &elemMat[(c-cStart)*totDim*totDim], ADD_VALUES)); 4174 } 4175 } 4176 /* Cleanup */ 4177 PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 4178 PetscCall(PetscQuadratureDestroy(&qGeom)); 4179 if (hasFV) PetscCall(MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_FALSE)); 4180 PetscCall(DMRestoreWorkArray(dm, Nf, MPIU_BOOL, &isFE)); 4181 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)); 4182 /* Compute boundary integrals */ 4183 /* PetscCall(DMPlexComputeBdJacobian_Internal(dm, X, X_t, t, X_tShift, Jac, JacP, ctx)); */ 4184 /* Assemble matrix */ 4185 if (assembleJac) {PetscCall(MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY));PetscCall(MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY));} 4186 PetscCall(MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY));PetscCall(MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY)); 4187 PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM,dm,0,0,0)); 4188 PetscFunctionReturn(0); 4189 } 4190 4191 /******** FEM Assembly Function ********/ 4192 4193 static PetscErrorCode DMConvertPlex_Internal(DM dm, DM *plex, PetscBool copy) 4194 { 4195 PetscBool isPlex; 4196 4197 PetscFunctionBegin; 4198 PetscCall(PetscObjectTypeCompare((PetscObject) dm, DMPLEX, &isPlex)); 4199 if (isPlex) { 4200 *plex = dm; 4201 PetscCall(PetscObjectReference((PetscObject) dm)); 4202 } else { 4203 PetscCall(PetscObjectQuery((PetscObject) dm, "dm_plex", (PetscObject *) plex)); 4204 if (!*plex) { 4205 PetscCall(DMConvert(dm,DMPLEX,plex)); 4206 PetscCall(PetscObjectCompose((PetscObject) dm, "dm_plex", (PetscObject) *plex)); 4207 if (copy) { 4208 PetscCall(DMCopyAuxiliaryVec(dm, *plex)); 4209 } 4210 } else { 4211 PetscCall(PetscObjectReference((PetscObject) *plex)); 4212 } 4213 } 4214 PetscFunctionReturn(0); 4215 } 4216 4217 /*@ 4218 DMPlexGetGeometryFVM - Return precomputed geometric data 4219 4220 Collective on DM 4221 4222 Input Parameter: 4223 . dm - The DM 4224 4225 Output Parameters: 4226 + facegeom - The values precomputed from face geometry 4227 . cellgeom - The values precomputed from cell geometry 4228 - minRadius - The minimum radius over the mesh of an inscribed sphere in a cell 4229 4230 Level: developer 4231 4232 .seealso: `DMTSSetRHSFunctionLocal()` 4233 @*/ 4234 PetscErrorCode DMPlexGetGeometryFVM(DM dm, Vec *facegeom, Vec *cellgeom, PetscReal *minRadius) 4235 { 4236 DM plex; 4237 4238 PetscFunctionBegin; 4239 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 4240 PetscCall(DMConvertPlex_Internal(dm,&plex,PETSC_TRUE)); 4241 PetscCall(DMPlexGetDataFVM(plex, NULL, cellgeom, facegeom, NULL)); 4242 if (minRadius) PetscCall(DMPlexGetMinRadius(plex, minRadius)); 4243 PetscCall(DMDestroy(&plex)); 4244 PetscFunctionReturn(0); 4245 } 4246 4247 /*@ 4248 DMPlexGetGradientDM - Return gradient data layout 4249 4250 Collective on DM 4251 4252 Input Parameters: 4253 + dm - The DM 4254 - fv - The PetscFV 4255 4256 Output Parameter: 4257 . dmGrad - The layout for gradient values 4258 4259 Level: developer 4260 4261 .seealso: `DMPlexGetGeometryFVM()` 4262 @*/ 4263 PetscErrorCode DMPlexGetGradientDM(DM dm, PetscFV fv, DM *dmGrad) 4264 { 4265 DM plex; 4266 PetscBool computeGradients; 4267 4268 PetscFunctionBegin; 4269 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 4270 PetscValidHeaderSpecific(fv,PETSCFV_CLASSID,2); 4271 PetscValidPointer(dmGrad,3); 4272 PetscCall(PetscFVGetComputeGradients(fv, &computeGradients)); 4273 if (!computeGradients) {*dmGrad = NULL; PetscFunctionReturn(0);} 4274 PetscCall(DMConvertPlex_Internal(dm,&plex,PETSC_TRUE)); 4275 PetscCall(DMPlexGetDataFVM(plex, fv, NULL, NULL, dmGrad)); 4276 PetscCall(DMDestroy(&plex)); 4277 PetscFunctionReturn(0); 4278 } 4279 4280 static PetscErrorCode DMPlexComputeBdResidual_Single_Internal(DM dm, PetscReal t, PetscWeakForm wf, PetscFormKey key, Vec locX, Vec locX_t, Vec locF, DMField coordField, IS facetIS) 4281 { 4282 DM_Plex *mesh = (DM_Plex *) dm->data; 4283 DM plex = NULL, plexA = NULL; 4284 DMEnclosureType encAux; 4285 PetscDS prob, probAux = NULL; 4286 PetscSection section, sectionAux = NULL; 4287 Vec locA = NULL; 4288 PetscScalar *u = NULL, *u_t = NULL, *a = NULL, *elemVec = NULL; 4289 PetscInt totDim, totDimAux = 0; 4290 4291 PetscFunctionBegin; 4292 PetscCall(DMConvert(dm, DMPLEX, &plex)); 4293 PetscCall(DMGetLocalSection(dm, §ion)); 4294 PetscCall(DMGetDS(dm, &prob)); 4295 PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 4296 PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &locA)); 4297 if (locA) { 4298 DM dmAux; 4299 4300 PetscCall(VecGetDM(locA, &dmAux)); 4301 PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 4302 PetscCall(DMConvert(dmAux, DMPLEX, &plexA)); 4303 PetscCall(DMGetDS(plexA, &probAux)); 4304 PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 4305 PetscCall(DMGetLocalSection(plexA, §ionAux)); 4306 } 4307 { 4308 PetscFEGeom *fgeom; 4309 PetscInt maxDegree; 4310 PetscQuadrature qGeom = NULL; 4311 IS pointIS; 4312 const PetscInt *points; 4313 PetscInt numFaces, face, Nq; 4314 4315 PetscCall(DMLabelGetStratumIS(key.label, key.value, &pointIS)); 4316 if (!pointIS) goto end; /* No points with that id on this process */ 4317 { 4318 IS isectIS; 4319 4320 /* TODO: Special cases of ISIntersect where it is quick to check a priori if one is a superset of the other */ 4321 PetscCall(ISIntersect_Caching_Internal(facetIS,pointIS,&isectIS)); 4322 PetscCall(ISDestroy(&pointIS)); 4323 pointIS = isectIS; 4324 } 4325 PetscCall(ISGetLocalSize(pointIS,&numFaces)); 4326 PetscCall(ISGetIndices(pointIS,&points)); 4327 PetscCall(PetscMalloc4(numFaces*totDim, &u, locX_t ? numFaces*totDim : 0, &u_t, numFaces*totDim, &elemVec, locA ? numFaces*totDimAux : 0, &a)); 4328 PetscCall(DMFieldGetDegree(coordField,pointIS,NULL,&maxDegree)); 4329 if (maxDegree <= 1) { 4330 PetscCall(DMFieldCreateDefaultQuadrature(coordField,pointIS,&qGeom)); 4331 } 4332 if (!qGeom) { 4333 PetscFE fe; 4334 4335 PetscCall(PetscDSGetDiscretization(prob, key.field, (PetscObject *) &fe)); 4336 PetscCall(PetscFEGetFaceQuadrature(fe, &qGeom)); 4337 PetscCall(PetscObjectReference((PetscObject)qGeom)); 4338 } 4339 PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL)); 4340 PetscCall(DMSNESGetFEGeom(coordField,pointIS,qGeom,PETSC_TRUE,&fgeom)); 4341 for (face = 0; face < numFaces; ++face) { 4342 const PetscInt point = points[face], *support; 4343 PetscScalar *x = NULL; 4344 PetscInt i; 4345 4346 PetscCall(DMPlexGetSupport(dm, point, &support)); 4347 PetscCall(DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x)); 4348 for (i = 0; i < totDim; ++i) u[face*totDim+i] = x[i]; 4349 PetscCall(DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x)); 4350 if (locX_t) { 4351 PetscCall(DMPlexVecGetClosure(plex, section, locX_t, support[0], NULL, &x)); 4352 for (i = 0; i < totDim; ++i) u_t[face*totDim+i] = x[i]; 4353 PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, support[0], NULL, &x)); 4354 } 4355 if (locA) { 4356 PetscInt subp; 4357 4358 PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp)); 4359 PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x)); 4360 for (i = 0; i < totDimAux; ++i) a[face*totDimAux+i] = x[i]; 4361 PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x)); 4362 } 4363 } 4364 PetscCall(PetscArrayzero(elemVec, numFaces*totDim)); 4365 { 4366 PetscFE fe; 4367 PetscInt Nb; 4368 PetscFEGeom *chunkGeom = NULL; 4369 /* Conforming batches */ 4370 PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize; 4371 /* Remainder */ 4372 PetscInt Nr, offset; 4373 4374 PetscCall(PetscDSGetDiscretization(prob, key.field, (PetscObject *) &fe)); 4375 PetscCall(PetscFEGetDimension(fe, &Nb)); 4376 PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 4377 /* TODO: documentation is unclear about what is going on with these numbers: how should Nb / Nq factor in ? */ 4378 blockSize = Nb; 4379 batchSize = numBlocks * blockSize; 4380 PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 4381 numChunks = numFaces / (numBatches*batchSize); 4382 Ne = numChunks*numBatches*batchSize; 4383 Nr = numFaces % (numBatches*batchSize); 4384 offset = numFaces - Nr; 4385 PetscCall(PetscFEGeomGetChunk(fgeom,0,offset,&chunkGeom)); 4386 PetscCall(PetscFEIntegrateBdResidual(prob, wf, key, Ne, chunkGeom, u, u_t, probAux, a, t, elemVec)); 4387 PetscCall(PetscFEGeomRestoreChunk(fgeom, 0, offset, &chunkGeom)); 4388 PetscCall(PetscFEGeomGetChunk(fgeom,offset,numFaces,&chunkGeom)); 4389 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])); 4390 PetscCall(PetscFEGeomRestoreChunk(fgeom,offset,numFaces,&chunkGeom)); 4391 } 4392 for (face = 0; face < numFaces; ++face) { 4393 const PetscInt point = points[face], *support; 4394 4395 if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(point, "BdResidual", totDim, &elemVec[face*totDim])); 4396 PetscCall(DMPlexGetSupport(plex, point, &support)); 4397 PetscCall(DMPlexVecSetClosure(plex, NULL, locF, support[0], &elemVec[face*totDim], ADD_ALL_VALUES)); 4398 } 4399 PetscCall(DMSNESRestoreFEGeom(coordField,pointIS,qGeom,PETSC_TRUE,&fgeom)); 4400 PetscCall(PetscQuadratureDestroy(&qGeom)); 4401 PetscCall(ISRestoreIndices(pointIS, &points)); 4402 PetscCall(ISDestroy(&pointIS)); 4403 PetscCall(PetscFree4(u, u_t, elemVec, a)); 4404 } 4405 end: 4406 PetscCall(DMDestroy(&plex)); 4407 PetscCall(DMDestroy(&plexA)); 4408 PetscFunctionReturn(0); 4409 } 4410 4411 PetscErrorCode DMPlexComputeBdResidualSingle(DM dm, PetscReal t, PetscWeakForm wf, PetscFormKey key, Vec locX, Vec locX_t, Vec locF) 4412 { 4413 DMField coordField; 4414 DMLabel depthLabel; 4415 IS facetIS; 4416 PetscInt dim; 4417 4418 PetscFunctionBegin; 4419 PetscCall(DMGetDimension(dm, &dim)); 4420 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 4421 PetscCall(DMLabelGetStratumIS(depthLabel, dim-1, &facetIS)); 4422 PetscCall(DMGetCoordinateField(dm, &coordField)); 4423 PetscCall(DMPlexComputeBdResidual_Single_Internal(dm, t, wf, key, locX, locX_t, locF, coordField, facetIS)); 4424 PetscCall(ISDestroy(&facetIS)); 4425 PetscFunctionReturn(0); 4426 } 4427 4428 PetscErrorCode DMPlexComputeBdResidual_Internal(DM dm, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user) 4429 { 4430 PetscDS prob; 4431 PetscInt numBd, bd; 4432 DMField coordField = NULL; 4433 IS facetIS = NULL; 4434 DMLabel depthLabel; 4435 PetscInt dim; 4436 4437 PetscFunctionBegin; 4438 PetscCall(DMGetDS(dm, &prob)); 4439 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 4440 PetscCall(DMGetDimension(dm, &dim)); 4441 PetscCall(DMLabelGetStratumIS(depthLabel,dim - 1,&facetIS)); 4442 PetscCall(PetscDSGetNumBoundary(prob, &numBd)); 4443 for (bd = 0; bd < numBd; ++bd) { 4444 PetscWeakForm wf; 4445 DMBoundaryConditionType type; 4446 DMLabel label; 4447 const PetscInt *values; 4448 PetscInt field, numValues, v; 4449 PetscObject obj; 4450 PetscClassId id; 4451 PetscFormKey key; 4452 4453 PetscCall(PetscDSGetBoundary(prob, bd, &wf, &type, NULL, &label, &numValues, &values, &field, NULL, NULL, NULL, NULL, NULL)); 4454 PetscCall(PetscDSGetDiscretization(prob, field, &obj)); 4455 PetscCall(PetscObjectGetClassId(obj, &id)); 4456 if ((id != PETSCFE_CLASSID) || (type & DM_BC_ESSENTIAL)) continue; 4457 if (!facetIS) { 4458 DMLabel depthLabel; 4459 PetscInt dim; 4460 4461 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 4462 PetscCall(DMGetDimension(dm, &dim)); 4463 PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 4464 } 4465 PetscCall(DMGetCoordinateField(dm, &coordField)); 4466 for (v = 0; v < numValues; ++v) { 4467 key.label = label; 4468 key.value = values[v]; 4469 key.field = field; 4470 key.part = 0; 4471 PetscCall(DMPlexComputeBdResidual_Single_Internal(dm, t, wf, key, locX, locX_t, locF, coordField, facetIS)); 4472 } 4473 } 4474 PetscCall(ISDestroy(&facetIS)); 4475 PetscFunctionReturn(0); 4476 } 4477 4478 PetscErrorCode DMPlexComputeResidual_Internal(DM dm, PetscFormKey key, IS cellIS, PetscReal time, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user) 4479 { 4480 DM_Plex *mesh = (DM_Plex *) dm->data; 4481 const char *name = "Residual"; 4482 DM dmAux = NULL; 4483 DM dmGrad = NULL; 4484 DMLabel ghostLabel = NULL; 4485 PetscDS ds = NULL; 4486 PetscDS dsAux = NULL; 4487 PetscSection section = NULL; 4488 PetscBool useFEM = PETSC_FALSE; 4489 PetscBool useFVM = PETSC_FALSE; 4490 PetscBool isImplicit = (locX_t || time == PETSC_MIN_REAL) ? PETSC_TRUE : PETSC_FALSE; 4491 PetscFV fvm = NULL; 4492 PetscFVCellGeom *cgeomFVM = NULL; 4493 PetscFVFaceGeom *fgeomFVM = NULL; 4494 DMField coordField = NULL; 4495 Vec locA, cellGeometryFVM = NULL, faceGeometryFVM = NULL, grad, locGrad = NULL; 4496 PetscScalar *u = NULL, *u_t, *a, *uL, *uR; 4497 IS chunkIS; 4498 const PetscInt *cells; 4499 PetscInt cStart, cEnd, numCells; 4500 PetscInt Nf, f, totDim, totDimAux, numChunks, cellChunkSize, faceChunkSize, chunk, fStart, fEnd; 4501 PetscInt maxDegree = PETSC_MAX_INT; 4502 PetscQuadrature affineQuad = NULL, *quads = NULL; 4503 PetscFEGeom *affineGeom = NULL, **geoms = NULL; 4504 4505 PetscFunctionBegin; 4506 PetscCall(PetscLogEventBegin(DMPLEX_ResidualFEM,dm,0,0,0)); 4507 /* TODO The places where we have to use isFE are probably the member functions for the PetscDisc class */ 4508 /* TODO The FVM geometry is over-manipulated. Make the precalc functions return exactly what we need */ 4509 /* FEM+FVM */ 4510 PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 4511 PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 4512 /* 1: Get sizes from dm and dmAux */ 4513 PetscCall(DMGetLocalSection(dm, §ion)); 4514 PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 4515 PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds)); 4516 PetscCall(PetscDSGetNumFields(ds, &Nf)); 4517 PetscCall(PetscDSGetTotalDimension(ds, &totDim)); 4518 PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &locA)); 4519 if (locA) { 4520 PetscInt subcell; 4521 PetscCall(VecGetDM(locA, &dmAux)); 4522 PetscCall(DMGetEnclosurePoint(dmAux, dm, DM_ENC_UNKNOWN, cells ? cells[cStart] : cStart, &subcell)); 4523 PetscCall(DMGetCellDS(dmAux, subcell, &dsAux)); 4524 PetscCall(PetscDSGetTotalDimension(dsAux, &totDimAux)); 4525 } 4526 /* 2: Get geometric data */ 4527 for (f = 0; f < Nf; ++f) { 4528 PetscObject obj; 4529 PetscClassId id; 4530 PetscBool fimp; 4531 4532 PetscCall(PetscDSGetImplicit(ds, f, &fimp)); 4533 if (isImplicit != fimp) continue; 4534 PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 4535 PetscCall(PetscObjectGetClassId(obj, &id)); 4536 if (id == PETSCFE_CLASSID) {useFEM = PETSC_TRUE;} 4537 if (id == PETSCFV_CLASSID) {useFVM = PETSC_TRUE; fvm = (PetscFV) obj;} 4538 } 4539 if (useFEM) { 4540 PetscCall(DMGetCoordinateField(dm, &coordField)); 4541 PetscCall(DMFieldGetDegree(coordField,cellIS,NULL,&maxDegree)); 4542 if (maxDegree <= 1) { 4543 PetscCall(DMFieldCreateDefaultQuadrature(coordField,cellIS,&affineQuad)); 4544 if (affineQuad) { 4545 PetscCall(DMSNESGetFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom)); 4546 } 4547 } else { 4548 PetscCall(PetscCalloc2(Nf,&quads,Nf,&geoms)); 4549 for (f = 0; f < Nf; ++f) { 4550 PetscObject obj; 4551 PetscClassId id; 4552 PetscBool fimp; 4553 4554 PetscCall(PetscDSGetImplicit(ds, f, &fimp)); 4555 if (isImplicit != fimp) continue; 4556 PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 4557 PetscCall(PetscObjectGetClassId(obj, &id)); 4558 if (id == PETSCFE_CLASSID) { 4559 PetscFE fe = (PetscFE) obj; 4560 4561 PetscCall(PetscFEGetQuadrature(fe, &quads[f])); 4562 PetscCall(PetscObjectReference((PetscObject)quads[f])); 4563 PetscCall(DMSNESGetFEGeom(coordField,cellIS,quads[f],PETSC_FALSE,&geoms[f])); 4564 } 4565 } 4566 } 4567 } 4568 if (useFVM) { 4569 PetscCall(DMPlexGetGeometryFVM(dm, &faceGeometryFVM, &cellGeometryFVM, NULL)); 4570 PetscCall(VecGetArrayRead(faceGeometryFVM, (const PetscScalar **) &fgeomFVM)); 4571 PetscCall(VecGetArrayRead(cellGeometryFVM, (const PetscScalar **) &cgeomFVM)); 4572 /* Reconstruct and limit cell gradients */ 4573 PetscCall(DMPlexGetGradientDM(dm, fvm, &dmGrad)); 4574 if (dmGrad) { 4575 PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 4576 PetscCall(DMGetGlobalVector(dmGrad, &grad)); 4577 PetscCall(DMPlexReconstructGradients_Internal(dm, fvm, fStart, fEnd, faceGeometryFVM, cellGeometryFVM, locX, grad)); 4578 /* Communicate gradient values */ 4579 PetscCall(DMGetLocalVector(dmGrad, &locGrad)); 4580 PetscCall(DMGlobalToLocalBegin(dmGrad, grad, INSERT_VALUES, locGrad)); 4581 PetscCall(DMGlobalToLocalEnd(dmGrad, grad, INSERT_VALUES, locGrad)); 4582 PetscCall(DMRestoreGlobalVector(dmGrad, &grad)); 4583 } 4584 /* Handle non-essential (e.g. outflow) boundary values */ 4585 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_FALSE, locX, time, faceGeometryFVM, cellGeometryFVM, locGrad)); 4586 } 4587 /* Loop over chunks */ 4588 if (useFEM) PetscCall(ISCreate(PETSC_COMM_SELF, &chunkIS)); 4589 numCells = cEnd - cStart; 4590 numChunks = 1; 4591 cellChunkSize = numCells/numChunks; 4592 faceChunkSize = (fEnd - fStart)/numChunks; 4593 numChunks = PetscMin(1,numCells); 4594 for (chunk = 0; chunk < numChunks; ++chunk) { 4595 PetscScalar *elemVec, *fluxL, *fluxR; 4596 PetscReal *vol; 4597 PetscFVFaceGeom *fgeom; 4598 PetscInt cS = cStart+chunk*cellChunkSize, cE = PetscMin(cS+cellChunkSize, cEnd), numCells = cE - cS, c; 4599 PetscInt fS = fStart+chunk*faceChunkSize, fE = PetscMin(fS+faceChunkSize, fEnd), numFaces = 0, face; 4600 4601 /* Extract field coefficients */ 4602 if (useFEM) { 4603 PetscCall(ISGetPointSubrange(chunkIS, cS, cE, cells)); 4604 PetscCall(DMPlexGetCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a)); 4605 PetscCall(DMGetWorkArray(dm, numCells*totDim, MPIU_SCALAR, &elemVec)); 4606 PetscCall(PetscArrayzero(elemVec, numCells*totDim)); 4607 } 4608 if (useFVM) { 4609 PetscCall(DMPlexGetFaceFields(dm, fS, fE, locX, locX_t, faceGeometryFVM, cellGeometryFVM, locGrad, &numFaces, &uL, &uR)); 4610 PetscCall(DMPlexGetFaceGeometry(dm, fS, fE, faceGeometryFVM, cellGeometryFVM, &numFaces, &fgeom, &vol)); 4611 PetscCall(DMGetWorkArray(dm, numFaces*totDim, MPIU_SCALAR, &fluxL)); 4612 PetscCall(DMGetWorkArray(dm, numFaces*totDim, MPIU_SCALAR, &fluxR)); 4613 PetscCall(PetscArrayzero(fluxL, numFaces*totDim)); 4614 PetscCall(PetscArrayzero(fluxR, numFaces*totDim)); 4615 } 4616 /* TODO We will interlace both our field coefficients (u, u_t, uL, uR, etc.) and our output (elemVec, fL, fR). I think this works */ 4617 /* Loop over fields */ 4618 for (f = 0; f < Nf; ++f) { 4619 PetscObject obj; 4620 PetscClassId id; 4621 PetscBool fimp; 4622 PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset; 4623 4624 key.field = f; 4625 PetscCall(PetscDSGetImplicit(ds, f, &fimp)); 4626 if (isImplicit != fimp) continue; 4627 PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 4628 PetscCall(PetscObjectGetClassId(obj, &id)); 4629 if (id == PETSCFE_CLASSID) { 4630 PetscFE fe = (PetscFE) obj; 4631 PetscFEGeom *geom = affineGeom ? affineGeom : geoms[f]; 4632 PetscFEGeom *chunkGeom = NULL; 4633 PetscQuadrature quad = affineQuad ? affineQuad : quads[f]; 4634 PetscInt Nq, Nb; 4635 4636 PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 4637 PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL)); 4638 PetscCall(PetscFEGetDimension(fe, &Nb)); 4639 blockSize = Nb; 4640 batchSize = numBlocks * blockSize; 4641 PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 4642 numChunks = numCells / (numBatches*batchSize); 4643 Ne = numChunks*numBatches*batchSize; 4644 Nr = numCells % (numBatches*batchSize); 4645 offset = numCells - Nr; 4646 /* Integrate FE residual to get elemVec (need fields at quadrature points) */ 4647 /* 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) */ 4648 PetscCall(PetscFEGeomGetChunk(geom,0,offset,&chunkGeom)); 4649 PetscCall(PetscFEIntegrateResidual(ds, key, Ne, chunkGeom, u, u_t, dsAux, a, t, elemVec)); 4650 PetscCall(PetscFEGeomGetChunk(geom,offset,numCells,&chunkGeom)); 4651 PetscCall(PetscFEIntegrateResidual(ds, key, Nr, chunkGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, dsAux, &a[offset*totDimAux], t, &elemVec[offset*totDim])); 4652 PetscCall(PetscFEGeomRestoreChunk(geom,offset,numCells,&chunkGeom)); 4653 } else if (id == PETSCFV_CLASSID) { 4654 PetscFV fv = (PetscFV) obj; 4655 4656 Ne = numFaces; 4657 /* Riemann solve over faces (need fields at face centroids) */ 4658 /* We need to evaluate FE fields at those coordinates */ 4659 PetscCall(PetscFVIntegrateRHSFunction(fv, ds, f, Ne, fgeom, vol, uL, uR, fluxL, fluxR)); 4660 } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, f); 4661 } 4662 /* Loop over domain */ 4663 if (useFEM) { 4664 /* Add elemVec to locX */ 4665 for (c = cS; c < cE; ++c) { 4666 const PetscInt cell = cells ? cells[c] : c; 4667 const PetscInt cind = c - cStart; 4668 4669 if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, name, totDim, &elemVec[cind*totDim])); 4670 if (ghostLabel) { 4671 PetscInt ghostVal; 4672 4673 PetscCall(DMLabelGetValue(ghostLabel,cell,&ghostVal)); 4674 if (ghostVal > 0) continue; 4675 } 4676 PetscCall(DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind*totDim], ADD_ALL_VALUES)); 4677 } 4678 } 4679 if (useFVM) { 4680 PetscScalar *fa; 4681 PetscInt iface; 4682 4683 PetscCall(VecGetArray(locF, &fa)); 4684 for (f = 0; f < Nf; ++f) { 4685 PetscFV fv; 4686 PetscObject obj; 4687 PetscClassId id; 4688 PetscInt foff, pdim; 4689 4690 PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 4691 PetscCall(PetscDSGetFieldOffset(ds, f, &foff)); 4692 PetscCall(PetscObjectGetClassId(obj, &id)); 4693 if (id != PETSCFV_CLASSID) continue; 4694 fv = (PetscFV) obj; 4695 PetscCall(PetscFVGetNumComponents(fv, &pdim)); 4696 /* Accumulate fluxes to cells */ 4697 for (face = fS, iface = 0; face < fE; ++face) { 4698 const PetscInt *scells; 4699 PetscScalar *fL = NULL, *fR = NULL; 4700 PetscInt ghost, d, nsupp, nchild; 4701 4702 PetscCall(DMLabelGetValue(ghostLabel, face, &ghost)); 4703 PetscCall(DMPlexGetSupportSize(dm, face, &nsupp)); 4704 PetscCall(DMPlexGetTreeChildren(dm, face, &nchild, NULL)); 4705 if (ghost >= 0 || nsupp > 2 || nchild > 0) continue; 4706 PetscCall(DMPlexGetSupport(dm, face, &scells)); 4707 PetscCall(DMLabelGetValue(ghostLabel,scells[0],&ghost)); 4708 if (ghost <= 0) PetscCall(DMPlexPointLocalFieldRef(dm, scells[0], f, fa, &fL)); 4709 PetscCall(DMLabelGetValue(ghostLabel,scells[1],&ghost)); 4710 if (ghost <= 0) PetscCall(DMPlexPointLocalFieldRef(dm, scells[1], f, fa, &fR)); 4711 for (d = 0; d < pdim; ++d) { 4712 if (fL) fL[d] -= fluxL[iface*totDim+foff+d]; 4713 if (fR) fR[d] += fluxR[iface*totDim+foff+d]; 4714 } 4715 ++iface; 4716 } 4717 } 4718 PetscCall(VecRestoreArray(locF, &fa)); 4719 } 4720 /* Handle time derivative */ 4721 if (locX_t) { 4722 PetscScalar *x_t, *fa; 4723 4724 PetscCall(VecGetArray(locF, &fa)); 4725 PetscCall(VecGetArray(locX_t, &x_t)); 4726 for (f = 0; f < Nf; ++f) { 4727 PetscFV fv; 4728 PetscObject obj; 4729 PetscClassId id; 4730 PetscInt pdim, d; 4731 4732 PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 4733 PetscCall(PetscObjectGetClassId(obj, &id)); 4734 if (id != PETSCFV_CLASSID) continue; 4735 fv = (PetscFV) obj; 4736 PetscCall(PetscFVGetNumComponents(fv, &pdim)); 4737 for (c = cS; c < cE; ++c) { 4738 const PetscInt cell = cells ? cells[c] : c; 4739 PetscScalar *u_t, *r; 4740 4741 if (ghostLabel) { 4742 PetscInt ghostVal; 4743 4744 PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal)); 4745 if (ghostVal > 0) continue; 4746 } 4747 PetscCall(DMPlexPointLocalFieldRead(dm, cell, f, x_t, &u_t)); 4748 PetscCall(DMPlexPointLocalFieldRef(dm, cell, f, fa, &r)); 4749 for (d = 0; d < pdim; ++d) r[d] += u_t[d]; 4750 } 4751 } 4752 PetscCall(VecRestoreArray(locX_t, &x_t)); 4753 PetscCall(VecRestoreArray(locF, &fa)); 4754 } 4755 if (useFEM) { 4756 PetscCall(DMPlexRestoreCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a)); 4757 PetscCall(DMRestoreWorkArray(dm, numCells*totDim, MPIU_SCALAR, &elemVec)); 4758 } 4759 if (useFVM) { 4760 PetscCall(DMPlexRestoreFaceFields(dm, fS, fE, locX, locX_t, faceGeometryFVM, cellGeometryFVM, locGrad, &numFaces, &uL, &uR)); 4761 PetscCall(DMPlexRestoreFaceGeometry(dm, fS, fE, faceGeometryFVM, cellGeometryFVM, &numFaces, &fgeom, &vol)); 4762 PetscCall(DMRestoreWorkArray(dm, numFaces*totDim, MPIU_SCALAR, &fluxL)); 4763 PetscCall(DMRestoreWorkArray(dm, numFaces*totDim, MPIU_SCALAR, &fluxR)); 4764 if (dmGrad) PetscCall(DMRestoreLocalVector(dmGrad, &locGrad)); 4765 } 4766 } 4767 if (useFEM) PetscCall(ISDestroy(&chunkIS)); 4768 PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 4769 4770 if (useFEM) { 4771 PetscCall(DMPlexComputeBdResidual_Internal(dm, locX, locX_t, t, locF, user)); 4772 4773 if (maxDegree <= 1) { 4774 PetscCall(DMSNESRestoreFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom)); 4775 PetscCall(PetscQuadratureDestroy(&affineQuad)); 4776 } else { 4777 for (f = 0; f < Nf; ++f) { 4778 PetscCall(DMSNESRestoreFEGeom(coordField,cellIS,quads[f],PETSC_FALSE,&geoms[f])); 4779 PetscCall(PetscQuadratureDestroy(&quads[f])); 4780 } 4781 PetscCall(PetscFree2(quads,geoms)); 4782 } 4783 } 4784 4785 /* FEM */ 4786 /* 1: Get sizes from dm and dmAux */ 4787 /* 2: Get geometric data */ 4788 /* 3: Handle boundary values */ 4789 /* 4: Loop over domain */ 4790 /* Extract coefficients */ 4791 /* Loop over fields */ 4792 /* Set tiling for FE*/ 4793 /* Integrate FE residual to get elemVec */ 4794 /* Loop over subdomain */ 4795 /* Loop over quad points */ 4796 /* Transform coords to real space */ 4797 /* Evaluate field and aux fields at point */ 4798 /* Evaluate residual at point */ 4799 /* Transform residual to real space */ 4800 /* Add residual to elemVec */ 4801 /* Loop over domain */ 4802 /* Add elemVec to locX */ 4803 4804 /* FVM */ 4805 /* Get geometric data */ 4806 /* If using gradients */ 4807 /* Compute gradient data */ 4808 /* Loop over domain faces */ 4809 /* Count computational faces */ 4810 /* Reconstruct cell gradient */ 4811 /* Loop over domain cells */ 4812 /* Limit cell gradients */ 4813 /* Handle boundary values */ 4814 /* Loop over domain faces */ 4815 /* Read out field, centroid, normal, volume for each side of face */ 4816 /* Riemann solve over faces */ 4817 /* Loop over domain faces */ 4818 /* Accumulate fluxes to cells */ 4819 /* TODO Change printFEM to printDisc here */ 4820 if (mesh->printFEM) { 4821 Vec locFbc; 4822 PetscInt pStart, pEnd, p, maxDof; 4823 PetscScalar *zeroes; 4824 4825 PetscCall(VecDuplicate(locF,&locFbc)); 4826 PetscCall(VecCopy(locF,locFbc)); 4827 PetscCall(PetscSectionGetChart(section,&pStart,&pEnd)); 4828 PetscCall(PetscSectionGetMaxDof(section,&maxDof)); 4829 PetscCall(PetscCalloc1(maxDof,&zeroes)); 4830 for (p = pStart; p < pEnd; p++) { 4831 PetscCall(VecSetValuesSection(locFbc,section,p,zeroes,INSERT_BC_VALUES)); 4832 } 4833 PetscCall(PetscFree(zeroes)); 4834 PetscCall(DMPrintLocalVec(dm, name, mesh->printTol, locFbc)); 4835 PetscCall(VecDestroy(&locFbc)); 4836 } 4837 PetscCall(PetscLogEventEnd(DMPLEX_ResidualFEM,dm,0,0,0)); 4838 PetscFunctionReturn(0); 4839 } 4840 4841 /* 4842 1) Allow multiple kernels for BdResidual for hybrid DS 4843 4844 DONE 2) Get out dsAux for either side at the same time as cohesive cell dsAux 4845 4846 DONE 3) Change DMGetCellFields() to get different aux data a[] for each side 4847 - I think I just need to replace a[] with the closure from each face 4848 4849 4) Run both kernels for each non-hybrid field with correct dsAux, and then hybrid field as before 4850 */ 4851 PetscErrorCode DMPlexComputeResidual_Hybrid_Internal(DM dm, PetscFormKey key[], IS cellIS, PetscReal time, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user) 4852 { 4853 DM_Plex *mesh = (DM_Plex *) dm->data; 4854 const char *name = "Hybrid Residual"; 4855 DM dmAux[3] = {NULL, NULL, NULL}; 4856 DMLabel ghostLabel = NULL; 4857 PetscDS ds = NULL; 4858 PetscDS dsAux[3] = {NULL, NULL, NULL}; 4859 Vec locA[3] = {NULL, NULL, NULL}; 4860 PetscSection section = NULL; 4861 DMField coordField = NULL; 4862 PetscScalar *u = NULL, *u_t, *a[3]; 4863 PetscScalar *elemVec; 4864 IS chunkIS; 4865 const PetscInt *cells; 4866 PetscInt *faces; 4867 PetscInt cStart, cEnd, numCells; 4868 PetscInt Nf, f, totDim, totDimAux[3], numChunks, cellChunkSize, chunk; 4869 PetscInt maxDegree = PETSC_MAX_INT; 4870 PetscQuadrature affineQuad = NULL, *quads = NULL; 4871 PetscFEGeom *affineGeom = NULL, **geoms = NULL; 4872 4873 PetscFunctionBegin; 4874 if ((key[0].label == key[1].label) && (key[0].value == key[1].value) && (key[0].part == key[1].part)) { 4875 const char *name; 4876 PetscCall(PetscObjectGetName((PetscObject) key[0].label, &name)); 4877 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); 4878 } 4879 PetscCall(PetscLogEventBegin(DMPLEX_ResidualFEM,dm,0,0,0)); 4880 /* TODO The places where we have to use isFE are probably the member functions for the PetscDisc class */ 4881 /* FEM */ 4882 PetscCall(ISGetLocalSize(cellIS, &numCells)); 4883 PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 4884 /* 1: Get sizes from dm and dmAux */ 4885 PetscCall(DMGetSection(dm, §ion)); 4886 PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 4887 PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds)); 4888 PetscCall(PetscDSGetNumFields(ds, &Nf)); 4889 PetscCall(PetscDSGetTotalDimension(ds, &totDim)); 4890 PetscCall(DMGetAuxiliaryVec(dm, key[2].label, key[2].value, key[2].part, &locA[2])); 4891 if (locA[2]) { 4892 const PetscInt cellStart = cells ? cells[cStart] : cStart; 4893 4894 PetscCall(VecGetDM(locA[2], &dmAux[2])); 4895 PetscCall(DMGetCellDS(dmAux[2], cellStart, &dsAux[2])); 4896 PetscCall(PetscDSGetTotalDimension(dsAux[2], &totDimAux[2])); 4897 { 4898 const PetscInt *cone; 4899 PetscInt c; 4900 4901 PetscCall(DMPlexGetCone(dm, cellStart, &cone)); 4902 for (c = 0; c < 2; ++c) { 4903 const PetscInt *support; 4904 PetscInt ssize, s; 4905 4906 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 4907 PetscCall(DMPlexGetSupportSize(dm, cone[c], &ssize)); 4908 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); 4909 if (support[0] == cellStart) s = 1; 4910 else if (support[1] == cellStart) s = 0; 4911 else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " does not have cell %" PetscInt_FMT " in its support", cone[c], cellStart); 4912 PetscCall(DMGetAuxiliaryVec(dm, key[c].label, key[c].value, key[c].part, &locA[c])); 4913 if (locA[c]) PetscCall(VecGetDM(locA[c], &dmAux[c])); 4914 else {dmAux[c] = dmAux[2];} 4915 PetscCall(DMGetCellDS(dmAux[c], support[s], &dsAux[c])); 4916 PetscCall(PetscDSGetTotalDimension(dsAux[c], &totDimAux[c])); 4917 } 4918 } 4919 } 4920 /* 2: Setup geometric data */ 4921 PetscCall(DMGetCoordinateField(dm, &coordField)); 4922 PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 4923 if (maxDegree > 1) { 4924 PetscCall(PetscCalloc2(Nf, &quads, Nf, &geoms)); 4925 for (f = 0; f < Nf; ++f) { 4926 PetscFE fe; 4927 4928 PetscCall(PetscDSGetDiscretization(ds, f, (PetscObject *) &fe)); 4929 if (fe) { 4930 PetscCall(PetscFEGetQuadrature(fe, &quads[f])); 4931 PetscCall(PetscObjectReference((PetscObject) quads[f])); 4932 } 4933 } 4934 } 4935 /* Loop over chunks */ 4936 cellChunkSize = numCells; 4937 numChunks = !numCells ? 0 : PetscCeilReal(((PetscReal) numCells)/cellChunkSize); 4938 PetscCall(PetscCalloc1(1*cellChunkSize, &faces)); 4939 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 1*cellChunkSize, faces, PETSC_USE_POINTER, &chunkIS)); 4940 /* Extract field coefficients */ 4941 /* NOTE This needs the end cap faces to have identical orientations */ 4942 PetscCall(DMPlexGetCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2])); 4943 PetscCall(DMPlexGetHybridAuxFields(dm, dmAux, dsAux, cellIS, locA, a)); 4944 PetscCall(DMGetWorkArray(dm, cellChunkSize*totDim, MPIU_SCALAR, &elemVec)); 4945 for (chunk = 0; chunk < numChunks; ++chunk) { 4946 PetscInt cS = cStart+chunk*cellChunkSize, cE = PetscMin(cS+cellChunkSize, cEnd), numCells = cE - cS, c; 4947 4948 PetscCall(PetscMemzero(elemVec, cellChunkSize*totDim * sizeof(PetscScalar))); 4949 /* Get faces */ 4950 for (c = cS; c < cE; ++c) { 4951 const PetscInt cell = cells ? cells[c] : c; 4952 const PetscInt *cone; 4953 PetscCall(DMPlexGetCone(dm, cell, &cone)); 4954 faces[0*cellChunkSize+(c-cS)] = cone[0]; 4955 /*faces[1*cellChunkSize+(c-cS)] = cone[1];*/ 4956 } 4957 PetscCall(ISGeneralSetIndices(chunkIS, 1*cellChunkSize, faces, PETSC_USE_POINTER)); 4958 /* Get geometric data */ 4959 if (maxDegree <= 1) { 4960 if (!affineQuad) PetscCall(DMFieldCreateDefaultQuadrature(coordField, chunkIS, &affineQuad)); 4961 if (affineQuad) PetscCall(DMSNESGetFEGeom(coordField, chunkIS, affineQuad, PETSC_TRUE, &affineGeom)); 4962 } else { 4963 for (f = 0; f < Nf; ++f) { 4964 if (quads[f]) PetscCall(DMSNESGetFEGeom(coordField, chunkIS, quads[f], PETSC_TRUE, &geoms[f])); 4965 } 4966 } 4967 /* Loop over fields */ 4968 for (f = 0; f < Nf; ++f) { 4969 PetscFE fe; 4970 PetscFEGeom *geom = affineGeom ? affineGeom : geoms[f]; 4971 PetscFEGeom *chunkGeom = NULL, *remGeom = NULL; 4972 PetscQuadrature quad = affineQuad ? affineQuad : quads[f]; 4973 PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset, Nq, Nb; 4974 PetscBool isCohesiveField; 4975 4976 PetscCall(PetscDSGetDiscretization(ds, f, (PetscObject *) &fe)); 4977 if (!fe) continue; 4978 PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 4979 PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL)); 4980 PetscCall(PetscFEGetDimension(fe, &Nb)); 4981 blockSize = Nb; 4982 batchSize = numBlocks * blockSize; 4983 PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 4984 numChunks = numCells / (numBatches*batchSize); 4985 Ne = numChunks*numBatches*batchSize; 4986 Nr = numCells % (numBatches*batchSize); 4987 offset = numCells - Nr; 4988 PetscCall(PetscFEGeomGetChunk(geom,0,offset,&chunkGeom)); 4989 PetscCall(PetscFEGeomGetChunk(geom,offset,numCells,&remGeom)); 4990 PetscCall(PetscDSGetCohesive(ds, f, &isCohesiveField)); 4991 chunkGeom->isCohesive = remGeom->isCohesive = PETSC_TRUE; 4992 key[0].field = f; 4993 key[1].field = f; 4994 key[2].field = f; 4995 PetscCall(PetscFEIntegrateHybridResidual(ds, key[0], 0, Ne, chunkGeom, u, u_t, dsAux[0], a[0], t, elemVec)); 4996 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])); 4997 PetscCall(PetscFEIntegrateHybridResidual(ds, key[1], 1, Ne, chunkGeom, u, u_t, dsAux[1], a[1], t, elemVec)); 4998 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])); 4999 PetscCall(PetscFEIntegrateHybridResidual(ds, key[2], 2, Ne, chunkGeom, u, u_t, dsAux[2], a[2], t, elemVec)); 5000 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])); 5001 PetscCall(PetscFEGeomRestoreChunk(geom,offset,numCells,&remGeom)); 5002 PetscCall(PetscFEGeomRestoreChunk(geom,0,offset,&chunkGeom)); 5003 } 5004 /* Add elemVec to locX */ 5005 for (c = cS; c < cE; ++c) { 5006 const PetscInt cell = cells ? cells[c] : c; 5007 const PetscInt cind = c - cStart; 5008 5009 if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, name, totDim, &elemVec[cind*totDim])); 5010 if (ghostLabel) { 5011 PetscInt ghostVal; 5012 5013 PetscCall(DMLabelGetValue(ghostLabel,cell,&ghostVal)); 5014 if (ghostVal > 0) continue; 5015 } 5016 PetscCall(DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind*totDim], ADD_ALL_VALUES)); 5017 } 5018 } 5019 PetscCall(DMPlexRestoreCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2])); 5020 PetscCall(DMPlexRestoreHybridAuxFields(dmAux, dsAux, cellIS, locA, a)); 5021 PetscCall(DMRestoreWorkArray(dm, numCells*totDim, MPIU_SCALAR, &elemVec)); 5022 PetscCall(PetscFree(faces)); 5023 PetscCall(ISDestroy(&chunkIS)); 5024 PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 5025 if (maxDegree <= 1) { 5026 PetscCall(DMSNESRestoreFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom)); 5027 PetscCall(PetscQuadratureDestroy(&affineQuad)); 5028 } else { 5029 for (f = 0; f < Nf; ++f) { 5030 if (geoms) PetscCall(DMSNESRestoreFEGeom(coordField,cellIS,quads[f],PETSC_FALSE,&geoms[f])); 5031 if (quads) PetscCall(PetscQuadratureDestroy(&quads[f])); 5032 } 5033 PetscCall(PetscFree2(quads,geoms)); 5034 } 5035 PetscCall(PetscLogEventEnd(DMPLEX_ResidualFEM,dm,0,0,0)); 5036 PetscFunctionReturn(0); 5037 } 5038 5039 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) 5040 { 5041 DM_Plex *mesh = (DM_Plex *) dm->data; 5042 DM plex = NULL, plexA = NULL, tdm; 5043 DMEnclosureType encAux; 5044 PetscDS prob, probAux = NULL; 5045 PetscSection section, sectionAux = NULL; 5046 PetscSection globalSection; 5047 Vec locA = NULL, tv; 5048 PetscScalar *u = NULL, *u_t = NULL, *a = NULL, *elemMat = NULL; 5049 PetscInt v; 5050 PetscInt Nf, totDim, totDimAux = 0; 5051 PetscBool transform; 5052 5053 PetscFunctionBegin; 5054 PetscCall(DMConvert(dm, DMPLEX, &plex)); 5055 PetscCall(DMHasBasisTransform(dm, &transform)); 5056 PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm)); 5057 PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 5058 PetscCall(DMGetLocalSection(dm, §ion)); 5059 PetscCall(DMGetDS(dm, &prob)); 5060 PetscCall(PetscDSGetNumFields(prob, &Nf)); 5061 PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 5062 PetscCall(DMGetAuxiliaryVec(dm, label, values[0], 0, &locA)); 5063 if (locA) { 5064 DM dmAux; 5065 5066 PetscCall(VecGetDM(locA, &dmAux)); 5067 PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 5068 PetscCall(DMConvert(dmAux, DMPLEX, &plexA)); 5069 PetscCall(DMGetDS(plexA, &probAux)); 5070 PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 5071 PetscCall(DMGetLocalSection(plexA, §ionAux)); 5072 } 5073 5074 PetscCall(DMGetGlobalSection(dm, &globalSection)); 5075 for (v = 0; v < numValues; ++v) { 5076 PetscFEGeom *fgeom; 5077 PetscInt maxDegree; 5078 PetscQuadrature qGeom = NULL; 5079 IS pointIS; 5080 const PetscInt *points; 5081 PetscFormKey key; 5082 PetscInt numFaces, face, Nq; 5083 5084 key.label = label; 5085 key.value = values[v]; 5086 key.part = 0; 5087 PetscCall(DMLabelGetStratumIS(label, values[v], &pointIS)); 5088 if (!pointIS) continue; /* No points with that id on this process */ 5089 { 5090 IS isectIS; 5091 5092 /* TODO: Special cases of ISIntersect where it is quick to check a prior if one is a superset of the other */ 5093 PetscCall(ISIntersect_Caching_Internal(facetIS,pointIS,&isectIS)); 5094 PetscCall(ISDestroy(&pointIS)); 5095 pointIS = isectIS; 5096 } 5097 PetscCall(ISGetLocalSize(pointIS, &numFaces)); 5098 PetscCall(ISGetIndices(pointIS, &points)); 5099 PetscCall(PetscMalloc4(numFaces*totDim, &u, locX_t ? numFaces*totDim : 0, &u_t, numFaces*totDim*totDim, &elemMat, locA ? numFaces*totDimAux : 0, &a)); 5100 PetscCall(DMFieldGetDegree(coordField,pointIS,NULL,&maxDegree)); 5101 if (maxDegree <= 1) { 5102 PetscCall(DMFieldCreateDefaultQuadrature(coordField,pointIS,&qGeom)); 5103 } 5104 if (!qGeom) { 5105 PetscFE fe; 5106 5107 PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fe)); 5108 PetscCall(PetscFEGetFaceQuadrature(fe, &qGeom)); 5109 PetscCall(PetscObjectReference((PetscObject)qGeom)); 5110 } 5111 PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL)); 5112 PetscCall(DMSNESGetFEGeom(coordField,pointIS,qGeom,PETSC_TRUE,&fgeom)); 5113 for (face = 0; face < numFaces; ++face) { 5114 const PetscInt point = points[face], *support; 5115 PetscScalar *x = NULL; 5116 PetscInt i; 5117 5118 PetscCall(DMPlexGetSupport(dm, point, &support)); 5119 PetscCall(DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x)); 5120 for (i = 0; i < totDim; ++i) u[face*totDim+i] = x[i]; 5121 PetscCall(DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x)); 5122 if (locX_t) { 5123 PetscCall(DMPlexVecGetClosure(plex, section, locX_t, support[0], NULL, &x)); 5124 for (i = 0; i < totDim; ++i) u_t[face*totDim+i] = x[i]; 5125 PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, support[0], NULL, &x)); 5126 } 5127 if (locA) { 5128 PetscInt subp; 5129 PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp)); 5130 PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x)); 5131 for (i = 0; i < totDimAux; ++i) a[face*totDimAux+i] = x[i]; 5132 PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x)); 5133 } 5134 } 5135 PetscCall(PetscArrayzero(elemMat, numFaces*totDim*totDim)); 5136 { 5137 PetscFE fe; 5138 PetscInt Nb; 5139 /* Conforming batches */ 5140 PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize; 5141 /* Remainder */ 5142 PetscFEGeom *chunkGeom = NULL; 5143 PetscInt fieldJ, Nr, offset; 5144 5145 PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fe)); 5146 PetscCall(PetscFEGetDimension(fe, &Nb)); 5147 PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 5148 blockSize = Nb; 5149 batchSize = numBlocks * blockSize; 5150 PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 5151 numChunks = numFaces / (numBatches*batchSize); 5152 Ne = numChunks*numBatches*batchSize; 5153 Nr = numFaces % (numBatches*batchSize); 5154 offset = numFaces - Nr; 5155 PetscCall(PetscFEGeomGetChunk(fgeom,0,offset,&chunkGeom)); 5156 for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 5157 key.field = fieldI*Nf+fieldJ; 5158 PetscCall(PetscFEIntegrateBdJacobian(prob, wf, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat)); 5159 } 5160 PetscCall(PetscFEGeomGetChunk(fgeom,offset,numFaces,&chunkGeom)); 5161 for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 5162 key.field = fieldI*Nf+fieldJ; 5163 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])); 5164 } 5165 PetscCall(PetscFEGeomRestoreChunk(fgeom,offset,numFaces,&chunkGeom)); 5166 } 5167 for (face = 0; face < numFaces; ++face) { 5168 const PetscInt point = points[face], *support; 5169 5170 /* Transform to global basis before insertion in Jacobian */ 5171 PetscCall(DMPlexGetSupport(plex, point, &support)); 5172 if (transform) PetscCall(DMPlexBasisTransformPointTensor_Internal(dm, tdm, tv, support[0], PETSC_TRUE, totDim, &elemMat[face*totDim*totDim])); 5173 if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(point, "BdJacobian", totDim, totDim, &elemMat[face*totDim*totDim])); 5174 PetscCall(DMPlexMatSetClosure(plex, section, globalSection, JacP, support[0], &elemMat[face*totDim*totDim], ADD_VALUES)); 5175 } 5176 PetscCall(DMSNESRestoreFEGeom(coordField,pointIS,qGeom,PETSC_TRUE,&fgeom)); 5177 PetscCall(PetscQuadratureDestroy(&qGeom)); 5178 PetscCall(ISRestoreIndices(pointIS, &points)); 5179 PetscCall(ISDestroy(&pointIS)); 5180 PetscCall(PetscFree4(u, u_t, elemMat, a)); 5181 } 5182 if (plex) PetscCall(DMDestroy(&plex)); 5183 if (plexA) PetscCall(DMDestroy(&plexA)); 5184 PetscFunctionReturn(0); 5185 } 5186 5187 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) 5188 { 5189 DMField coordField; 5190 DMLabel depthLabel; 5191 IS facetIS; 5192 PetscInt dim; 5193 5194 PetscFunctionBegin; 5195 PetscCall(DMGetDimension(dm, &dim)); 5196 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 5197 PetscCall(DMLabelGetStratumIS(depthLabel, dim-1, &facetIS)); 5198 PetscCall(DMGetCoordinateField(dm, &coordField)); 5199 PetscCall(DMPlexComputeBdJacobian_Single_Internal(dm, t, wf, label, numValues, values, field, locX, locX_t, X_tShift, Jac, JacP, coordField, facetIS)); 5200 PetscCall(ISDestroy(&facetIS)); 5201 PetscFunctionReturn(0); 5202 } 5203 5204 PetscErrorCode DMPlexComputeBdJacobian_Internal(DM dm, Vec locX, Vec locX_t, PetscReal t, PetscReal X_tShift, Mat Jac, Mat JacP, void *user) 5205 { 5206 PetscDS prob; 5207 PetscInt dim, numBd, bd; 5208 DMLabel depthLabel; 5209 DMField coordField = NULL; 5210 IS facetIS; 5211 5212 PetscFunctionBegin; 5213 PetscCall(DMGetDS(dm, &prob)); 5214 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 5215 PetscCall(DMGetDimension(dm, &dim)); 5216 PetscCall(DMLabelGetStratumIS(depthLabel, dim-1, &facetIS)); 5217 PetscCall(PetscDSGetNumBoundary(prob, &numBd)); 5218 PetscCall(DMGetCoordinateField(dm, &coordField)); 5219 for (bd = 0; bd < numBd; ++bd) { 5220 PetscWeakForm wf; 5221 DMBoundaryConditionType type; 5222 DMLabel label; 5223 const PetscInt *values; 5224 PetscInt fieldI, numValues; 5225 PetscObject obj; 5226 PetscClassId id; 5227 5228 PetscCall(PetscDSGetBoundary(prob, bd, &wf, &type, NULL, &label, &numValues, &values, &fieldI, NULL, NULL, NULL, NULL, NULL)); 5229 PetscCall(PetscDSGetDiscretization(prob, fieldI, &obj)); 5230 PetscCall(PetscObjectGetClassId(obj, &id)); 5231 if ((id != PETSCFE_CLASSID) || (type & DM_BC_ESSENTIAL)) continue; 5232 PetscCall(DMPlexComputeBdJacobian_Single_Internal(dm, t, wf, label, numValues, values, fieldI, locX, locX_t, X_tShift, Jac, JacP, coordField, facetIS)); 5233 } 5234 PetscCall(ISDestroy(&facetIS)); 5235 PetscFunctionReturn(0); 5236 } 5237 5238 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) 5239 { 5240 DM_Plex *mesh = (DM_Plex *) dm->data; 5241 const char *name = "Jacobian"; 5242 DM dmAux = NULL, plex, tdm; 5243 DMEnclosureType encAux; 5244 Vec A, tv; 5245 DMField coordField; 5246 PetscDS prob, probAux = NULL; 5247 PetscSection section, globalSection, sectionAux; 5248 PetscScalar *elemMat, *elemMatP, *elemMatD, *u, *u_t, *a = NULL; 5249 const PetscInt *cells; 5250 PetscInt Nf, fieldI, fieldJ; 5251 PetscInt totDim, totDimAux, cStart, cEnd, numCells, c; 5252 PetscBool hasJac, hasPrec, hasDyn, hasFV = PETSC_FALSE, transform; 5253 5254 PetscFunctionBegin; 5255 PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM,dm,0,0,0)); 5256 PetscCall(ISGetLocalSize(cellIS, &numCells)); 5257 PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 5258 PetscCall(DMHasBasisTransform(dm, &transform)); 5259 PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm)); 5260 PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 5261 PetscCall(DMGetLocalSection(dm, §ion)); 5262 PetscCall(DMGetGlobalSection(dm, &globalSection)); 5263 PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob)); 5264 PetscCall(PetscDSGetNumFields(prob, &Nf)); 5265 PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 5266 PetscCall(PetscDSHasJacobian(prob, &hasJac)); 5267 PetscCall(PetscDSHasJacobianPreconditioner(prob, &hasPrec)); 5268 /* user passed in the same matrix, avoid double contributions and 5269 only assemble the Jacobian */ 5270 if (hasJac && Jac == JacP) hasPrec = PETSC_FALSE; 5271 PetscCall(PetscDSHasDynamicJacobian(prob, &hasDyn)); 5272 hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE; 5273 PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &A)); 5274 if (A) { 5275 PetscCall(VecGetDM(A, &dmAux)); 5276 PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 5277 PetscCall(DMConvert(dmAux, DMPLEX, &plex)); 5278 PetscCall(DMGetLocalSection(plex, §ionAux)); 5279 PetscCall(DMGetDS(dmAux, &probAux)); 5280 PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 5281 } 5282 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)); 5283 if (dmAux) PetscCall(PetscMalloc1(numCells*totDimAux, &a)); 5284 PetscCall(DMGetCoordinateField(dm, &coordField)); 5285 for (c = cStart; c < cEnd; ++c) { 5286 const PetscInt cell = cells ? cells[c] : c; 5287 const PetscInt cind = c - cStart; 5288 PetscScalar *x = NULL, *x_t = NULL; 5289 PetscInt i; 5290 5291 PetscCall(DMPlexVecGetClosure(dm, section, X, cell, NULL, &x)); 5292 for (i = 0; i < totDim; ++i) u[cind*totDim+i] = x[i]; 5293 PetscCall(DMPlexVecRestoreClosure(dm, section, X, cell, NULL, &x)); 5294 if (X_t) { 5295 PetscCall(DMPlexVecGetClosure(dm, section, X_t, cell, NULL, &x_t)); 5296 for (i = 0; i < totDim; ++i) u_t[cind*totDim+i] = x_t[i]; 5297 PetscCall(DMPlexVecRestoreClosure(dm, section, X_t, cell, NULL, &x_t)); 5298 } 5299 if (dmAux) { 5300 PetscInt subcell; 5301 PetscCall(DMGetEnclosurePoint(dmAux, dm, encAux, cell, &subcell)); 5302 PetscCall(DMPlexVecGetClosure(plex, sectionAux, A, subcell, NULL, &x)); 5303 for (i = 0; i < totDimAux; ++i) a[cind*totDimAux+i] = x[i]; 5304 PetscCall(DMPlexVecRestoreClosure(plex, sectionAux, A, subcell, NULL, &x)); 5305 } 5306 } 5307 if (hasJac) PetscCall(PetscArrayzero(elemMat, numCells*totDim*totDim)); 5308 if (hasPrec) PetscCall(PetscArrayzero(elemMatP, numCells*totDim*totDim)); 5309 if (hasDyn) PetscCall(PetscArrayzero(elemMatD, numCells*totDim*totDim)); 5310 for (fieldI = 0; fieldI < Nf; ++fieldI) { 5311 PetscClassId id; 5312 PetscFE fe; 5313 PetscQuadrature qGeom = NULL; 5314 PetscInt Nb; 5315 /* Conforming batches */ 5316 PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize; 5317 /* Remainder */ 5318 PetscInt Nr, offset, Nq; 5319 PetscInt maxDegree; 5320 PetscFEGeom *cgeomFEM, *chunkGeom = NULL, *remGeom = NULL; 5321 5322 PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fe)); 5323 PetscCall(PetscObjectGetClassId((PetscObject) fe, &id)); 5324 if (id == PETSCFV_CLASSID) {hasFV = PETSC_TRUE; continue;} 5325 PetscCall(PetscFEGetDimension(fe, &Nb)); 5326 PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 5327 PetscCall(DMFieldGetDegree(coordField,cellIS,NULL,&maxDegree)); 5328 if (maxDegree <= 1) { 5329 PetscCall(DMFieldCreateDefaultQuadrature(coordField,cellIS,&qGeom)); 5330 } 5331 if (!qGeom) { 5332 PetscCall(PetscFEGetQuadrature(fe,&qGeom)); 5333 PetscCall(PetscObjectReference((PetscObject)qGeom)); 5334 } 5335 PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL)); 5336 PetscCall(DMSNESGetFEGeom(coordField,cellIS,qGeom,PETSC_FALSE,&cgeomFEM)); 5337 blockSize = Nb; 5338 batchSize = numBlocks * blockSize; 5339 PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 5340 numChunks = numCells / (numBatches*batchSize); 5341 Ne = numChunks*numBatches*batchSize; 5342 Nr = numCells % (numBatches*batchSize); 5343 offset = numCells - Nr; 5344 PetscCall(PetscFEGeomGetChunk(cgeomFEM,0,offset,&chunkGeom)); 5345 PetscCall(PetscFEGeomGetChunk(cgeomFEM,offset,numCells,&remGeom)); 5346 for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 5347 key.field = fieldI*Nf+fieldJ; 5348 if (hasJac) { 5349 PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat)); 5350 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])); 5351 } 5352 if (hasPrec) { 5353 PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatP)); 5354 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])); 5355 } 5356 if (hasDyn) { 5357 PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatD)); 5358 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])); 5359 } 5360 } 5361 PetscCall(PetscFEGeomRestoreChunk(cgeomFEM,offset,numCells,&remGeom)); 5362 PetscCall(PetscFEGeomRestoreChunk(cgeomFEM,0,offset,&chunkGeom)); 5363 PetscCall(DMSNESRestoreFEGeom(coordField,cellIS,qGeom,PETSC_FALSE,&cgeomFEM)); 5364 PetscCall(PetscQuadratureDestroy(&qGeom)); 5365 } 5366 /* Add contribution from X_t */ 5367 if (hasDyn) {for (c = 0; c < numCells*totDim*totDim; ++c) elemMat[c] += X_tShift*elemMatD[c];} 5368 if (hasFV) { 5369 PetscClassId id; 5370 PetscFV fv; 5371 PetscInt offsetI, NcI, NbI = 1, fc, f; 5372 5373 for (fieldI = 0; fieldI < Nf; ++fieldI) { 5374 PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fv)); 5375 PetscCall(PetscDSGetFieldOffset(prob, fieldI, &offsetI)); 5376 PetscCall(PetscObjectGetClassId((PetscObject) fv, &id)); 5377 if (id != PETSCFV_CLASSID) continue; 5378 /* Put in the identity */ 5379 PetscCall(PetscFVGetNumComponents(fv, &NcI)); 5380 for (c = cStart; c < cEnd; ++c) { 5381 const PetscInt cind = c - cStart; 5382 const PetscInt eOffset = cind*totDim*totDim; 5383 for (fc = 0; fc < NcI; ++fc) { 5384 for (f = 0; f < NbI; ++f) { 5385 const PetscInt i = offsetI + f*NcI+fc; 5386 if (hasPrec) { 5387 if (hasJac) {elemMat[eOffset+i*totDim+i] = 1.0;} 5388 elemMatP[eOffset+i*totDim+i] = 1.0; 5389 } else {elemMat[eOffset+i*totDim+i] = 1.0;} 5390 } 5391 } 5392 } 5393 } 5394 /* No allocated space for FV stuff, so ignore the zero entries */ 5395 PetscCall(MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE)); 5396 } 5397 /* Insert values into matrix */ 5398 for (c = cStart; c < cEnd; ++c) { 5399 const PetscInt cell = cells ? cells[c] : c; 5400 const PetscInt cind = c - cStart; 5401 5402 /* Transform to global basis before insertion in Jacobian */ 5403 if (transform) PetscCall(DMPlexBasisTransformPointTensor_Internal(dm, tdm, tv, cell, PETSC_TRUE, totDim, &elemMat[cind*totDim*totDim])); 5404 if (hasPrec) { 5405 if (hasJac) { 5406 if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind*totDim*totDim])); 5407 PetscCall(DMPlexMatSetClosure(dm, section, globalSection, Jac, cell, &elemMat[cind*totDim*totDim], ADD_VALUES)); 5408 } 5409 if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatP[cind*totDim*totDim])); 5410 PetscCall(DMPlexMatSetClosure(dm, section, globalSection, JacP, cell, &elemMatP[cind*totDim*totDim], ADD_VALUES)); 5411 } else { 5412 if (hasJac) { 5413 if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind*totDim*totDim])); 5414 PetscCall(DMPlexMatSetClosure(dm, section, globalSection, JacP, cell, &elemMat[cind*totDim*totDim], ADD_VALUES)); 5415 } 5416 } 5417 } 5418 PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 5419 if (hasFV) PetscCall(MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_FALSE)); 5420 PetscCall(PetscFree5(u,u_t,elemMat,elemMatP,elemMatD)); 5421 if (dmAux) { 5422 PetscCall(PetscFree(a)); 5423 PetscCall(DMDestroy(&plex)); 5424 } 5425 /* Compute boundary integrals */ 5426 PetscCall(DMPlexComputeBdJacobian_Internal(dm, X, X_t, t, X_tShift, Jac, JacP, user)); 5427 /* Assemble matrix */ 5428 if (hasJac && hasPrec) { 5429 PetscCall(MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY)); 5430 PetscCall(MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY)); 5431 } 5432 PetscCall(MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY)); 5433 PetscCall(MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY)); 5434 PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM,dm,0,0,0)); 5435 PetscFunctionReturn(0); 5436 } 5437 5438 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) 5439 { 5440 DM_Plex *mesh = (DM_Plex *) dm->data; 5441 const char *name = "Hybrid Jacobian"; 5442 DM dmAux[3] = {NULL, NULL, NULL}; 5443 DMLabel ghostLabel = NULL; 5444 DM plex = NULL; 5445 DM plexA = NULL; 5446 PetscDS ds = NULL; 5447 PetscDS dsAux[3] = {NULL, NULL, NULL}; 5448 Vec locA[3] = {NULL, NULL, NULL}; 5449 PetscSection section = NULL; 5450 PetscSection sectionAux[3] = {NULL, NULL, NULL}; 5451 DMField coordField = NULL; 5452 PetscScalar *u = NULL, *u_t, *a[3]; 5453 PetscScalar *elemMat, *elemMatP; 5454 PetscSection globalSection; 5455 IS chunkIS; 5456 const PetscInt *cells; 5457 PetscInt *faces; 5458 PetscInt cStart, cEnd, numCells; 5459 PetscInt Nf, fieldI, fieldJ, totDim, totDimAux[3], numChunks, cellChunkSize, chunk; 5460 PetscInt maxDegree = PETSC_MAX_INT; 5461 PetscQuadrature affineQuad = NULL, *quads = NULL; 5462 PetscFEGeom *affineGeom = NULL, **geoms = NULL; 5463 PetscBool hasBdJac, hasBdPrec; 5464 5465 PetscFunctionBegin; 5466 if ((key[0].label == key[1].label) && (key[0].value == key[1].value) && (key[0].part == key[1].part)) { 5467 const char *name; 5468 PetscCall(PetscObjectGetName((PetscObject) key[0].label, &name)); 5469 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); 5470 } 5471 PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM,dm,0,0,0)); 5472 PetscCall(ISGetLocalSize(cellIS, &numCells)); 5473 PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 5474 PetscCall(DMConvert(dm, DMPLEX, &plex)); 5475 PetscCall(DMGetSection(dm, §ion)); 5476 PetscCall(DMGetGlobalSection(dm, &globalSection)); 5477 PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 5478 PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds)); 5479 PetscCall(PetscDSGetNumFields(ds, &Nf)); 5480 PetscCall(PetscDSGetTotalDimension(ds, &totDim)); 5481 PetscCall(PetscDSHasBdJacobian(ds, &hasBdJac)); 5482 PetscCall(PetscDSHasBdJacobianPreconditioner(ds, &hasBdPrec)); 5483 PetscCall(DMGetAuxiliaryVec(dm, key[2].label, key[2].value, key[2].part, &locA[2])); 5484 if (locA[2]) { 5485 const PetscInt cellStart = cells ? cells[cStart] : cStart; 5486 5487 PetscCall(VecGetDM(locA[2], &dmAux[2])); 5488 PetscCall(DMConvert(dmAux[2], DMPLEX, &plexA)); 5489 PetscCall(DMGetSection(dmAux[2], §ionAux[2])); 5490 PetscCall(DMGetCellDS(dmAux[2], cellStart, &dsAux[2])); 5491 PetscCall(PetscDSGetTotalDimension(dsAux[2], &totDimAux[2])); 5492 { 5493 const PetscInt *cone; 5494 PetscInt c; 5495 5496 PetscCall(DMPlexGetCone(dm, cellStart, &cone)); 5497 for (c = 0; c < 2; ++c) { 5498 const PetscInt *support; 5499 PetscInt ssize, s; 5500 5501 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 5502 PetscCall(DMPlexGetSupportSize(dm, cone[c], &ssize)); 5503 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); 5504 if (support[0] == cellStart) s = 1; 5505 else if (support[1] == cellStart) s = 0; 5506 else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %" PetscInt_FMT " does not have cell %" PetscInt_FMT " in its support", cone[c], cellStart); 5507 PetscCall(DMGetAuxiliaryVec(dm, key[c].label, key[c].value, key[c].part, &locA[c])); 5508 if (locA[c]) PetscCall(VecGetDM(locA[c], &dmAux[c])); 5509 else {dmAux[c] = dmAux[2];} 5510 PetscCall(DMGetCellDS(dmAux[c], support[s], &dsAux[c])); 5511 PetscCall(PetscDSGetTotalDimension(dsAux[c], &totDimAux[c])); 5512 } 5513 } 5514 } 5515 PetscCall(DMGetCoordinateField(dm, &coordField)); 5516 PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 5517 if (maxDegree > 1) { 5518 PetscInt f; 5519 PetscCall(PetscCalloc2(Nf, &quads, Nf, &geoms)); 5520 for (f = 0; f < Nf; ++f) { 5521 PetscFE fe; 5522 5523 PetscCall(PetscDSGetDiscretization(ds, f, (PetscObject *) &fe)); 5524 if (fe) { 5525 PetscCall(PetscFEGetQuadrature(fe, &quads[f])); 5526 PetscCall(PetscObjectReference((PetscObject) quads[f])); 5527 } 5528 } 5529 } 5530 cellChunkSize = numCells; 5531 numChunks = !numCells ? 0 : PetscCeilReal(((PetscReal) numCells)/cellChunkSize); 5532 PetscCall(PetscCalloc1(1*cellChunkSize, &faces)); 5533 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 1*cellChunkSize, faces, PETSC_USE_POINTER, &chunkIS)); 5534 PetscCall(DMPlexGetCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2])); 5535 PetscCall(DMPlexGetHybridAuxFields(dm, dmAux, dsAux, cellIS, locA, a)); 5536 PetscCall(DMGetWorkArray(dm, hasBdJac ? cellChunkSize*totDim*totDim : 0, MPIU_SCALAR, &elemMat)); 5537 PetscCall(DMGetWorkArray(dm, hasBdPrec ? cellChunkSize*totDim*totDim : 0, MPIU_SCALAR, &elemMatP)); 5538 for (chunk = 0; chunk < numChunks; ++chunk) { 5539 PetscInt cS = cStart+chunk*cellChunkSize, cE = PetscMin(cS+cellChunkSize, cEnd), numCells = cE - cS, c; 5540 5541 if (hasBdJac) PetscCall(PetscMemzero(elemMat, numCells*totDim*totDim * sizeof(PetscScalar))); 5542 if (hasBdPrec) PetscCall(PetscMemzero(elemMatP, numCells*totDim*totDim * sizeof(PetscScalar))); 5543 /* Get faces */ 5544 for (c = cS; c < cE; ++c) { 5545 const PetscInt cell = cells ? cells[c] : c; 5546 const PetscInt *cone; 5547 PetscCall(DMPlexGetCone(plex, cell, &cone)); 5548 faces[0*cellChunkSize+(c-cS)] = cone[0]; 5549 /*faces[2*cellChunkSize+(c-cS)] = cone[1];*/ 5550 } 5551 PetscCall(ISGeneralSetIndices(chunkIS, 1*cellChunkSize, faces, PETSC_USE_POINTER)); 5552 if (maxDegree <= 1) { 5553 if (!affineQuad) PetscCall(DMFieldCreateDefaultQuadrature(coordField, chunkIS, &affineQuad)); 5554 if (affineQuad) PetscCall(DMSNESGetFEGeom(coordField, chunkIS, affineQuad, PETSC_TRUE, &affineGeom)); 5555 } else { 5556 PetscInt f; 5557 for (f = 0; f < Nf; ++f) { 5558 if (quads[f]) PetscCall(DMSNESGetFEGeom(coordField, chunkIS, quads[f], PETSC_TRUE, &geoms[f])); 5559 } 5560 } 5561 5562 for (fieldI = 0; fieldI < Nf; ++fieldI) { 5563 PetscFE feI; 5564 PetscFEGeom *geom = affineGeom ? affineGeom : geoms[fieldI]; 5565 PetscFEGeom *chunkGeom = NULL, *remGeom = NULL; 5566 PetscQuadrature quad = affineQuad ? affineQuad : quads[fieldI]; 5567 PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset, Nq, Nb; 5568 PetscBool isCohesiveField; 5569 5570 PetscCall(PetscDSGetDiscretization(ds, fieldI, (PetscObject *) &feI)); 5571 if (!feI) continue; 5572 PetscCall(PetscFEGetTileSizes(feI, NULL, &numBlocks, NULL, &numBatches)); 5573 PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL)); 5574 PetscCall(PetscFEGetDimension(feI, &Nb)); 5575 blockSize = Nb; 5576 batchSize = numBlocks * blockSize; 5577 PetscCall(PetscFESetTileSizes(feI, blockSize, numBlocks, batchSize, numBatches)); 5578 numChunks = numCells / (numBatches*batchSize); 5579 Ne = numChunks*numBatches*batchSize; 5580 Nr = numCells % (numBatches*batchSize); 5581 offset = numCells - Nr; 5582 PetscCall(PetscFEGeomGetChunk(geom,0,offset,&chunkGeom)); 5583 PetscCall(PetscFEGeomGetChunk(geom,offset,numCells,&remGeom)); 5584 PetscCall(PetscDSGetCohesive(ds, fieldI, &isCohesiveField)); 5585 for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 5586 PetscFE feJ; 5587 5588 PetscCall(PetscDSGetDiscretization(ds, fieldJ, (PetscObject *) &feJ)); 5589 if (!feJ) continue; 5590 key[0].field = fieldI*Nf+fieldJ; 5591 key[1].field = fieldI*Nf+fieldJ; 5592 key[2].field = fieldI*Nf+fieldJ; 5593 if (hasBdJac) { 5594 PetscCall(PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN, key[0], 0, Ne, chunkGeom, u, u_t, dsAux[0], a[0], t, X_tShift, elemMat)); 5595 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])); 5596 PetscCall(PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN, key[1], 1, Ne, chunkGeom, u, u_t, dsAux[1], a[1], t, X_tShift, elemMat)); 5597 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])); 5598 } 5599 if (hasBdPrec) { 5600 PetscCall(PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN_PRE, key[0], 0, Ne, chunkGeom, u, u_t, dsAux[0], a[0], t, X_tShift, elemMatP)); 5601 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])); 5602 PetscCall(PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN_PRE, key[1], 1, Ne, chunkGeom, u, u_t, dsAux[1], a[1], t, X_tShift, elemMatP)); 5603 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])); 5604 } 5605 if (hasBdJac) { 5606 PetscCall(PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN, key[2], 2, Ne, chunkGeom, u, u_t, dsAux[2], a[2], t, X_tShift, elemMat)); 5607 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])); 5608 } 5609 if (hasBdPrec) { 5610 PetscCall(PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN_PRE, key[2], 2, Ne, chunkGeom, u, u_t, dsAux[2], a[2], t, X_tShift, elemMatP)); 5611 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])); 5612 } 5613 } 5614 PetscCall(PetscFEGeomRestoreChunk(geom,offset,numCells,&remGeom)); 5615 PetscCall(PetscFEGeomRestoreChunk(geom,0,offset,&chunkGeom)); 5616 } 5617 /* Insert values into matrix */ 5618 for (c = cS; c < cE; ++c) { 5619 const PetscInt cell = cells ? cells[c] : c; 5620 const PetscInt cind = c - cS; 5621 5622 if (hasBdPrec) { 5623 if (hasBdJac) { 5624 if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind*totDim*totDim])); 5625 PetscCall(DMPlexMatSetClosure(plex, section, globalSection, Jac, cell, &elemMat[cind*totDim*totDim], ADD_VALUES)); 5626 } 5627 if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatP[cind*totDim*totDim])); 5628 PetscCall(DMPlexMatSetClosure(plex, section, globalSection, JacP, cell, &elemMatP[cind*totDim*totDim], ADD_VALUES)); 5629 } else if (hasBdJac) { 5630 if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind*totDim*totDim])); 5631 PetscCall(DMPlexMatSetClosure(plex, section, globalSection, JacP, cell, &elemMat[cind*totDim*totDim], ADD_VALUES)); 5632 } 5633 } 5634 } 5635 PetscCall(DMPlexRestoreCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2])); 5636 PetscCall(DMPlexRestoreHybridAuxFields(dmAux, dsAux, cellIS, locA, a)); 5637 PetscCall(DMRestoreWorkArray(dm, hasBdJac ? cellChunkSize*totDim*totDim : 0, MPIU_SCALAR, &elemMat)); 5638 PetscCall(DMRestoreWorkArray(dm, hasBdPrec ? cellChunkSize*totDim*totDim : 0, MPIU_SCALAR, &elemMatP)); 5639 PetscCall(PetscFree(faces)); 5640 PetscCall(ISDestroy(&chunkIS)); 5641 PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 5642 if (maxDegree <= 1) { 5643 PetscCall(DMSNESRestoreFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom)); 5644 PetscCall(PetscQuadratureDestroy(&affineQuad)); 5645 } else { 5646 PetscInt f; 5647 for (f = 0; f < Nf; ++f) { 5648 if (geoms) PetscCall(DMSNESRestoreFEGeom(coordField,cellIS,quads[f],PETSC_FALSE, &geoms[f])); 5649 if (quads) PetscCall(PetscQuadratureDestroy(&quads[f])); 5650 } 5651 PetscCall(PetscFree2(quads,geoms)); 5652 } 5653 if (dmAux[2]) PetscCall(DMDestroy(&plexA)); 5654 PetscCall(DMDestroy(&plex)); 5655 /* Assemble matrix */ 5656 if (hasBdJac && hasBdPrec) { 5657 PetscCall(MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY)); 5658 PetscCall(MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY)); 5659 } 5660 PetscCall(MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY)); 5661 PetscCall(MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY)); 5662 PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM,dm,0,0,0)); 5663 PetscFunctionReturn(0); 5664 } 5665 5666 /* 5667 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. 5668 5669 Input Parameters: 5670 + dm - The mesh 5671 . key - The PetscWeakFormKey indcating where integration should happen 5672 . cellIS - The cells to integrate over 5673 . t - The time 5674 . X_tShift - The multiplier for the Jacobian with repsect to X_t 5675 . X - Local solution vector 5676 . X_t - Time-derivative of the local solution vector 5677 . Y - Local input vector 5678 - user - the user context 5679 5680 Output Parameter: 5681 . Z - Local output vector 5682 5683 Note: 5684 We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator, 5685 like a GPU, or vectorize on a multicore machine. 5686 */ 5687 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) 5688 { 5689 DM_Plex *mesh = (DM_Plex *) dm->data; 5690 const char *name = "Jacobian"; 5691 DM dmAux = NULL, plex, plexAux = NULL; 5692 DMEnclosureType encAux; 5693 Vec A; 5694 DMField coordField; 5695 PetscDS prob, probAux = NULL; 5696 PetscQuadrature quad; 5697 PetscSection section, globalSection, sectionAux; 5698 PetscScalar *elemMat, *elemMatD, *u, *u_t, *a = NULL, *y, *z; 5699 const PetscInt *cells; 5700 PetscInt Nf, fieldI, fieldJ; 5701 PetscInt totDim, totDimAux = 0, cStart, cEnd, numCells, c; 5702 PetscBool hasDyn; 5703 5704 PetscFunctionBegin; 5705 PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM,dm,0,0,0)); 5706 PetscCall(DMConvert(dm, DMPLEX, &plex)); 5707 if (!cellIS) { 5708 PetscInt depth; 5709 5710 PetscCall(DMPlexGetDepth(plex, &depth)); 5711 PetscCall(DMGetStratumIS(plex, "dim", depth, &cellIS)); 5712 if (!cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, &cellIS)); 5713 } else { 5714 PetscCall(PetscObjectReference((PetscObject) cellIS)); 5715 } 5716 PetscCall(ISGetLocalSize(cellIS, &numCells)); 5717 PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 5718 PetscCall(DMGetLocalSection(dm, §ion)); 5719 PetscCall(DMGetGlobalSection(dm, &globalSection)); 5720 PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob)); 5721 PetscCall(PetscDSGetNumFields(prob, &Nf)); 5722 PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 5723 PetscCall(PetscDSHasDynamicJacobian(prob, &hasDyn)); 5724 hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE; 5725 PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &A)); 5726 if (A) { 5727 PetscCall(VecGetDM(A, &dmAux)); 5728 PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 5729 PetscCall(DMConvert(dmAux, DMPLEX, &plexAux)); 5730 PetscCall(DMGetLocalSection(plexAux, §ionAux)); 5731 PetscCall(DMGetDS(dmAux, &probAux)); 5732 PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 5733 } 5734 PetscCall(VecSet(Z, 0.0)); 5735 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)); 5736 if (dmAux) PetscCall(PetscMalloc1(numCells*totDimAux, &a)); 5737 PetscCall(DMGetCoordinateField(dm, &coordField)); 5738 for (c = cStart; c < cEnd; ++c) { 5739 const PetscInt cell = cells ? cells[c] : c; 5740 const PetscInt cind = c - cStart; 5741 PetscScalar *x = NULL, *x_t = NULL; 5742 PetscInt i; 5743 5744 PetscCall(DMPlexVecGetClosure(plex, section, X, cell, NULL, &x)); 5745 for (i = 0; i < totDim; ++i) u[cind*totDim+i] = x[i]; 5746 PetscCall(DMPlexVecRestoreClosure(plex, section, X, cell, NULL, &x)); 5747 if (X_t) { 5748 PetscCall(DMPlexVecGetClosure(plex, section, X_t, cell, NULL, &x_t)); 5749 for (i = 0; i < totDim; ++i) u_t[cind*totDim+i] = x_t[i]; 5750 PetscCall(DMPlexVecRestoreClosure(plex, section, X_t, cell, NULL, &x_t)); 5751 } 5752 if (dmAux) { 5753 PetscInt subcell; 5754 PetscCall(DMGetEnclosurePoint(dmAux, dm, encAux, cell, &subcell)); 5755 PetscCall(DMPlexVecGetClosure(plexAux, sectionAux, A, subcell, NULL, &x)); 5756 for (i = 0; i < totDimAux; ++i) a[cind*totDimAux+i] = x[i]; 5757 PetscCall(DMPlexVecRestoreClosure(plexAux, sectionAux, A, subcell, NULL, &x)); 5758 } 5759 PetscCall(DMPlexVecGetClosure(plex, section, Y, cell, NULL, &x)); 5760 for (i = 0; i < totDim; ++i) y[cind*totDim+i] = x[i]; 5761 PetscCall(DMPlexVecRestoreClosure(plex, section, Y, cell, NULL, &x)); 5762 } 5763 PetscCall(PetscArrayzero(elemMat, numCells*totDim*totDim)); 5764 if (hasDyn) PetscCall(PetscArrayzero(elemMatD, numCells*totDim*totDim)); 5765 for (fieldI = 0; fieldI < Nf; ++fieldI) { 5766 PetscFE fe; 5767 PetscInt Nb; 5768 /* Conforming batches */ 5769 PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize; 5770 /* Remainder */ 5771 PetscInt Nr, offset, Nq; 5772 PetscQuadrature qGeom = NULL; 5773 PetscInt maxDegree; 5774 PetscFEGeom *cgeomFEM, *chunkGeom = NULL, *remGeom = NULL; 5775 5776 PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fe)); 5777 PetscCall(PetscFEGetQuadrature(fe, &quad)); 5778 PetscCall(PetscFEGetDimension(fe, &Nb)); 5779 PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 5780 PetscCall(DMFieldGetDegree(coordField,cellIS,NULL,&maxDegree)); 5781 if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField,cellIS,&qGeom)); 5782 if (!qGeom) { 5783 PetscCall(PetscFEGetQuadrature(fe,&qGeom)); 5784 PetscCall(PetscObjectReference((PetscObject)qGeom)); 5785 } 5786 PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL)); 5787 PetscCall(DMSNESGetFEGeom(coordField,cellIS,qGeom,PETSC_FALSE,&cgeomFEM)); 5788 blockSize = Nb; 5789 batchSize = numBlocks * blockSize; 5790 PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 5791 numChunks = numCells / (numBatches*batchSize); 5792 Ne = numChunks*numBatches*batchSize; 5793 Nr = numCells % (numBatches*batchSize); 5794 offset = numCells - Nr; 5795 PetscCall(PetscFEGeomGetChunk(cgeomFEM,0,offset,&chunkGeom)); 5796 PetscCall(PetscFEGeomGetChunk(cgeomFEM,offset,numCells,&remGeom)); 5797 for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 5798 key.field = fieldI*Nf + fieldJ; 5799 PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat)); 5800 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])); 5801 if (hasDyn) { 5802 PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatD)); 5803 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])); 5804 } 5805 } 5806 PetscCall(PetscFEGeomRestoreChunk(cgeomFEM,offset,numCells,&remGeom)); 5807 PetscCall(PetscFEGeomRestoreChunk(cgeomFEM,0,offset,&chunkGeom)); 5808 PetscCall(DMSNESRestoreFEGeom(coordField,cellIS,qGeom,PETSC_FALSE,&cgeomFEM)); 5809 PetscCall(PetscQuadratureDestroy(&qGeom)); 5810 } 5811 if (hasDyn) { 5812 for (c = 0; c < numCells*totDim*totDim; ++c) elemMat[c] += X_tShift*elemMatD[c]; 5813 } 5814 for (c = cStart; c < cEnd; ++c) { 5815 const PetscInt cell = cells ? cells[c] : c; 5816 const PetscInt cind = c - cStart; 5817 const PetscBLASInt M = totDim, one = 1; 5818 const PetscScalar a = 1.0, b = 0.0; 5819 5820 PetscStackCallBLAS("BLASgemv", BLASgemv_("N", &M, &M, &a, &elemMat[cind*totDim*totDim], &M, &y[cind*totDim], &one, &b, z, &one)); 5821 if (mesh->printFEM > 1) { 5822 PetscCall(DMPrintCellMatrix(c, name, totDim, totDim, &elemMat[cind*totDim*totDim])); 5823 PetscCall(DMPrintCellVector(c, "Y", totDim, &y[cind*totDim])); 5824 PetscCall(DMPrintCellVector(c, "Z", totDim, z)); 5825 } 5826 PetscCall(DMPlexVecSetClosure(dm, section, Z, cell, z, ADD_VALUES)); 5827 } 5828 PetscCall(PetscFree6(u,u_t,elemMat,elemMatD,y,z)); 5829 if (mesh->printFEM) { 5830 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)Z), "Z:\n")); 5831 PetscCall(VecView(Z, NULL)); 5832 } 5833 PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 5834 PetscCall(PetscFree(a)); 5835 PetscCall(ISDestroy(&cellIS)); 5836 PetscCall(DMDestroy(&plexAux)); 5837 PetscCall(DMDestroy(&plex)); 5838 PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM,dm,0,0,0)); 5839 PetscFunctionReturn(0); 5840 } 5841