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_%x\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 %D does not match context dimension %D", 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 %D is not in [0, Nf)", 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 %D 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 %D should be %D", c, lda); 581 r += fdof; 582 } 583 } 584 PetscCheck(r == lda,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of rows %D should be %D", 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 %D", 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 %D", 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 PetscErrorCode ierr; 1207 1208 PetscFunctionBegin; 1209 PetscCall(DMGetDimension(dm, &dim)); 1210 PetscCall(DMGetCoordinateDim(dm, &coordDim)); 1211 fegeom.dimEmbed = coordDim; 1212 PetscCall(DMGetLocalSection(dm, §ion)); 1213 PetscCall(PetscSectionGetNumFields(section, &numFields)); 1214 PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm)); 1215 PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 1216 PetscCall(DMHasBasisTransform(dm, &transform)); 1217 for (field = 0; field < numFields; ++field) { 1218 PetscObject obj; 1219 PetscClassId id; 1220 PetscInt Nc; 1221 1222 PetscCall(DMGetField(dm, field, NULL, &obj)); 1223 PetscCall(PetscObjectGetClassId(obj, &id)); 1224 if (id == PETSCFE_CLASSID) { 1225 PetscFE fe = (PetscFE) obj; 1226 1227 PetscCall(PetscFEGetQuadrature(fe, &quad)); 1228 PetscCall(PetscFEGetNumComponents(fe, &Nc)); 1229 } else if (id == PETSCFV_CLASSID) { 1230 PetscFV fv = (PetscFV) obj; 1231 1232 PetscCall(PetscFVGetQuadrature(fv, &quad)); 1233 PetscCall(PetscFVGetNumComponents(fv, &Nc)); 1234 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", field); 1235 numComponents += Nc; 1236 } 1237 PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, NULL, &quadWeights)); 1238 PetscCheck(!(qNc != 1) || !(qNc != numComponents),PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_SIZ, "Quadrature components %D != %D field components", qNc, numComponents); 1239 PetscCall(PetscMalloc6(numComponents,&funcVal,numComponents,&interpolant,coordDim*Nq,&coords,Nq,&fegeom.detJ,coordDim*coordDim*Nq,&fegeom.J,coordDim*coordDim*Nq,&fegeom.invJ)); 1240 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 1241 PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 1242 for (c = cStart; c < cEnd; ++c) { 1243 PetscScalar *x = NULL; 1244 PetscReal elemDiff = 0.0; 1245 PetscInt qc = 0; 1246 1247 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 1248 PetscCall(DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x)); 1249 1250 for (field = 0, fieldOffset = 0; field < numFields; ++field) { 1251 PetscObject obj; 1252 PetscClassId id; 1253 void * const ctx = ctxs ? ctxs[field] : NULL; 1254 PetscInt Nb, Nc, q, fc; 1255 1256 PetscCall(DMGetField(dm, field, NULL, &obj)); 1257 PetscCall(PetscObjectGetClassId(obj, &id)); 1258 if (id == PETSCFE_CLASSID) {PetscCall(PetscFEGetNumComponents((PetscFE) obj, &Nc));PetscCall(PetscFEGetDimension((PetscFE) obj, &Nb));} 1259 else if (id == PETSCFV_CLASSID) {PetscCall(PetscFVGetNumComponents((PetscFV) obj, &Nc));Nb = 1;} 1260 else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", field); 1261 if (debug) { 1262 char title[1024]; 1263 PetscCall(PetscSNPrintf(title, 1023, "Solution for Field %D", field)); 1264 PetscCall(DMPrintCellVector(c, title, Nb, &x[fieldOffset])); 1265 } 1266 for (q = 0; q < Nq; ++q) { 1267 PetscFEGeom qgeom; 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 %D, point %D", (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 PetscCall(ierr); 1287 } 1288 if (transform) PetscCall(DMPlexBasisTransformApply_Internal(dm, &coords[coordDim*q], PETSC_FALSE, Nc, funcVal, funcVal, dm->transformCtx)); 1289 if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolate_Static((PetscFE) obj, &x[fieldOffset], &qgeom, q, interpolant)); 1290 else if (id == PETSCFV_CLASSID) PetscCall(PetscFVInterpolate_Static((PetscFV) obj, &x[fieldOffset], q, interpolant)); 1291 else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %" PetscInt_FMT, field); 1292 for (fc = 0; fc < Nc; ++fc) { 1293 const PetscReal wt = quadWeights[q*qNc+(qNc == 1 ? 0 : qc+fc)]; 1294 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]), PetscRealPart(interpolant[fc]), PetscRealPart(funcVal[fc]))); 1295 elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc]))*wt*fegeom.detJ[q]; 1296 } 1297 } 1298 fieldOffset += Nb; 1299 qc += Nc; 1300 } 1301 PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x)); 1302 if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, " elem %" PetscInt_FMT " diff %g\n", c, (double)elemDiff)); 1303 localDiff += elemDiff; 1304 } 1305 PetscCall(PetscFree6(funcVal,interpolant,coords,fegeom.detJ,fegeom.J,fegeom.invJ)); 1306 PetscCall(MPIU_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm))); 1307 *diff = PetscSqrtReal(*diff); 1308 PetscFunctionReturn(0); 1309 } 1310 1311 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) 1312 { 1313 const PetscInt debug = ((DM_Plex*)dm->data)->printL2; 1314 DM tdm; 1315 PetscSection section; 1316 PetscQuadrature quad; 1317 Vec localX, tv; 1318 PetscScalar *funcVal, *interpolant; 1319 const PetscReal *quadWeights; 1320 PetscFEGeom fegeom; 1321 PetscReal *coords, *gcoords; 1322 PetscReal localDiff = 0.0; 1323 PetscInt dim, coordDim, qNc = 0, Nq = 0, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset; 1324 PetscBool transform; 1325 PetscErrorCode ierr; 1326 1327 PetscFunctionBegin; 1328 PetscCall(DMGetDimension(dm, &dim)); 1329 PetscCall(DMGetCoordinateDim(dm, &coordDim)); 1330 fegeom.dimEmbed = coordDim; 1331 PetscCall(DMGetLocalSection(dm, §ion)); 1332 PetscCall(PetscSectionGetNumFields(section, &numFields)); 1333 PetscCall(DMGetLocalVector(dm, &localX)); 1334 PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX)); 1335 PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX)); 1336 PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm)); 1337 PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 1338 PetscCall(DMHasBasisTransform(dm, &transform)); 1339 for (field = 0; field < numFields; ++field) { 1340 PetscFE fe; 1341 PetscInt Nc; 1342 1343 PetscCall(DMGetField(dm, field, NULL, (PetscObject *) &fe)); 1344 PetscCall(PetscFEGetQuadrature(fe, &quad)); 1345 PetscCall(PetscFEGetNumComponents(fe, &Nc)); 1346 numComponents += Nc; 1347 } 1348 PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, NULL, &quadWeights)); 1349 PetscCheck(!(qNc != 1) || !(qNc != numComponents),PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_SIZ, "Quadrature components %D != %D field components", qNc, numComponents); 1350 /* PetscCall(DMProjectFunctionLocal(dm, fe, funcs, INSERT_BC_VALUES, localX)); */ 1351 PetscCall(PetscMalloc6(numComponents,&funcVal,coordDim*Nq,&coords,coordDim*coordDim*Nq,&fegeom.J,coordDim*coordDim*Nq,&fegeom.invJ,numComponents*coordDim,&interpolant,Nq,&fegeom.detJ)); 1352 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 1353 for (c = cStart; c < cEnd; ++c) { 1354 PetscScalar *x = NULL; 1355 PetscReal elemDiff = 0.0; 1356 PetscInt qc = 0; 1357 1358 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 1359 PetscCall(DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x)); 1360 1361 for (field = 0, fieldOffset = 0; field < numFields; ++field) { 1362 PetscFE fe; 1363 void * const ctx = ctxs ? ctxs[field] : NULL; 1364 PetscInt Nb, Nc, q, fc; 1365 1366 PetscCall(DMGetField(dm, field, NULL, (PetscObject *) &fe)); 1367 PetscCall(PetscFEGetDimension(fe, &Nb)); 1368 PetscCall(PetscFEGetNumComponents(fe, &Nc)); 1369 if (debug) { 1370 char title[1024]; 1371 PetscCall(PetscSNPrintf(title, 1023, "Solution for Field %" PetscInt_FMT, field)); 1372 PetscCall(DMPrintCellVector(c, title, Nb, &x[fieldOffset])); 1373 } 1374 for (q = 0; q < Nq; ++q) { 1375 PetscFEGeom qgeom; 1376 1377 qgeom.dimEmbed = fegeom.dimEmbed; 1378 qgeom.J = &fegeom.J[q*coordDim*coordDim]; 1379 qgeom.invJ = &fegeom.invJ[q*coordDim*coordDim]; 1380 qgeom.detJ = &fegeom.detJ[q]; 1381 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); 1382 if (transform) { 1383 gcoords = &coords[coordDim*Nq]; 1384 PetscCall(DMPlexBasisTransformApplyReal_Internal(dm, &coords[coordDim*q], PETSC_TRUE, coordDim, &coords[coordDim*q], gcoords, dm->transformCtx)); 1385 } else { 1386 gcoords = &coords[coordDim*q]; 1387 } 1388 PetscCall(PetscArrayzero(funcVal,Nc)); 1389 ierr = (*funcs[field])(coordDim, time, gcoords, n, Nc, funcVal, ctx); 1390 if (ierr) { 1391 PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x)); 1392 PetscCall(DMRestoreLocalVector(dm, &localX)); 1393 PetscCall(PetscFree6(funcVal,coords,fegeom.J,fegeom.invJ,interpolant,fegeom.detJ)); 1394 PetscCall(ierr); 1395 } 1396 if (transform) PetscCall(DMPlexBasisTransformApply_Internal(dm, &coords[coordDim*q], PETSC_FALSE, Nc, funcVal, funcVal, dm->transformCtx)); 1397 PetscCall(PetscFEInterpolateGradient_Static(fe, 1, &x[fieldOffset], &qgeom, q, interpolant)); 1398 /* Overwrite with the dot product if the normal is given */ 1399 if (n) { 1400 for (fc = 0; fc < Nc; ++fc) { 1401 PetscScalar sum = 0.0; 1402 PetscInt d; 1403 for (d = 0; d < dim; ++d) sum += interpolant[fc*dim+d]*n[d]; 1404 interpolant[fc] = sum; 1405 } 1406 } 1407 for (fc = 0; fc < Nc; ++fc) { 1408 const PetscReal wt = quadWeights[q*qNc+(qNc == 1 ? 0 : qc+fc)]; 1409 if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, " elem %D fieldDer %D,%D diff %g\n", c, field, fc, (double)(PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc]))*wt*fegeom.detJ[q]))); 1410 elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc]))*wt*fegeom.detJ[q]; 1411 } 1412 } 1413 fieldOffset += Nb; 1414 qc += Nc; 1415 } 1416 PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x)); 1417 if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, " elem %D diff %g\n", c, (double)elemDiff)); 1418 localDiff += elemDiff; 1419 } 1420 PetscCall(PetscFree6(funcVal,coords,fegeom.J,fegeom.invJ,interpolant,fegeom.detJ)); 1421 PetscCall(DMRestoreLocalVector(dm, &localX)); 1422 PetscCall(MPIU_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm))); 1423 *diff = PetscSqrtReal(*diff); 1424 PetscFunctionReturn(0); 1425 } 1426 1427 PetscErrorCode DMComputeL2FieldDiff_Plex(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff) 1428 { 1429 const PetscInt debug = ((DM_Plex*)dm->data)->printL2; 1430 DM tdm; 1431 DMLabel depthLabel; 1432 PetscSection section; 1433 Vec localX, tv; 1434 PetscReal *localDiff; 1435 PetscInt dim, depth, dE, Nf, f, Nds, s; 1436 PetscBool transform; 1437 PetscErrorCode ierr; 1438 1439 PetscFunctionBegin; 1440 PetscCall(DMGetDimension(dm, &dim)); 1441 PetscCall(DMGetCoordinateDim(dm, &dE)); 1442 PetscCall(DMGetLocalSection(dm, §ion)); 1443 PetscCall(DMGetLocalVector(dm, &localX)); 1444 PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm)); 1445 PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 1446 PetscCall(DMHasBasisTransform(dm, &transform)); 1447 PetscCall(DMGetNumFields(dm, &Nf)); 1448 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 1449 PetscCall(DMLabelGetNumValues(depthLabel, &depth)); 1450 1451 PetscCall(VecSet(localX, 0.0)); 1452 PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX)); 1453 PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX)); 1454 PetscCall(DMProjectFunctionLocal(dm, time, funcs, ctxs, INSERT_BC_VALUES, localX)); 1455 PetscCall(DMGetNumDS(dm, &Nds)); 1456 PetscCall(PetscCalloc1(Nf, &localDiff)); 1457 for (s = 0; s < Nds; ++s) { 1458 PetscDS ds; 1459 DMLabel label; 1460 IS fieldIS, pointIS; 1461 const PetscInt *fields, *points = NULL; 1462 PetscQuadrature quad; 1463 const PetscReal *quadPoints, *quadWeights; 1464 PetscFEGeom fegeom; 1465 PetscReal *coords, *gcoords; 1466 PetscScalar *funcVal, *interpolant; 1467 PetscBool isCohesive; 1468 PetscInt qNc, Nq, totNc, cStart = 0, cEnd, c, dsNf; 1469 1470 PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds)); 1471 PetscCall(ISGetIndices(fieldIS, &fields)); 1472 PetscCall(PetscDSIsCohesive(ds, &isCohesive)); 1473 PetscCall(PetscDSGetNumFields(ds, &dsNf)); 1474 PetscCall(PetscDSGetTotalComponents(ds, &totNc)); 1475 PetscCall(PetscDSGetQuadrature(ds, &quad)); 1476 PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights)); 1477 PetscCheck(!(qNc != 1) || !(qNc != totNc),PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Quadrature components %D != %D field components", qNc, totNc); 1478 PetscCall(PetscCalloc6(totNc, &funcVal, totNc, &interpolant, dE*(Nq+1), &coords,Nq, &fegeom.detJ, dE*dE*Nq, &fegeom.J, dE*dE*Nq, &fegeom.invJ)); 1479 if (!label) { 1480 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 1481 } else { 1482 PetscCall(DMLabelGetStratumIS(label, 1, &pointIS)); 1483 PetscCall(ISGetLocalSize(pointIS, &cEnd)); 1484 PetscCall(ISGetIndices(pointIS, &points)); 1485 } 1486 for (c = cStart; c < cEnd; ++c) { 1487 const PetscInt cell = points ? points[c] : c; 1488 PetscScalar *x = NULL; 1489 const PetscInt *cone; 1490 PetscInt qc = 0, fOff = 0, dep; 1491 1492 PetscCall(DMLabelGetValue(depthLabel, cell, &dep)); 1493 if (dep != depth-1) continue; 1494 if (isCohesive) { 1495 PetscCall(DMPlexGetCone(dm, cell, &cone)); 1496 PetscCall(DMPlexComputeCellGeometryFEM(dm, cone[0], quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 1497 } else { 1498 PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 1499 } 1500 PetscCall(DMPlexVecGetClosure(dm, NULL, localX, cell, NULL, &x)); 1501 for (f = 0; f < dsNf; ++f) { 1502 PetscObject obj; 1503 PetscClassId id; 1504 void * const ctx = ctxs ? ctxs[fields[f]] : NULL; 1505 PetscInt Nb, Nc, q, fc; 1506 PetscReal elemDiff = 0.0; 1507 PetscBool cohesive; 1508 1509 PetscCall(PetscDSGetCohesive(ds, f, &cohesive)); 1510 if (isCohesive && !cohesive) continue; 1511 PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 1512 PetscCall(PetscObjectGetClassId(obj, &id)); 1513 if (id == PETSCFE_CLASSID) {PetscCall(PetscFEGetNumComponents((PetscFE) obj, &Nc));PetscCall(PetscFEGetDimension((PetscFE) obj, &Nb));} 1514 else if (id == PETSCFV_CLASSID) {PetscCall(PetscFVGetNumComponents((PetscFV) obj, &Nc));Nb = 1;} 1515 else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", fields[f]); 1516 if (debug) { 1517 char title[1024]; 1518 PetscCall(PetscSNPrintf(title, 1023, "Solution for Field %D", fields[f])); 1519 PetscCall(DMPrintCellVector(cell, title, Nb, &x[fOff])); 1520 } 1521 for (q = 0; q < Nq; ++q) { 1522 PetscFEGeom qgeom; 1523 1524 qgeom.dimEmbed = fegeom.dimEmbed; 1525 qgeom.J = &fegeom.J[q*dE*dE]; 1526 qgeom.invJ = &fegeom.invJ[q*dE*dE]; 1527 qgeom.detJ = &fegeom.detJ[q]; 1528 PetscCheck(fegeom.detJ[q] > 0.0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for cell %D, quadrature point %D", (double)fegeom.detJ[q], cell, q); 1529 if (transform) { 1530 gcoords = &coords[dE*Nq]; 1531 PetscCall(DMPlexBasisTransformApplyReal_Internal(dm, &coords[dE*q], PETSC_TRUE, dE, &coords[dE*q], gcoords, dm->transformCtx)); 1532 } else { 1533 gcoords = &coords[dE*q]; 1534 } 1535 for (fc = 0; fc < Nc; ++fc) funcVal[fc] = 0.; 1536 ierr = (*funcs[fields[f]])(dE, time, gcoords, Nc, funcVal, ctx); 1537 if (ierr) { 1538 PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, cell, NULL, &x)); 1539 PetscCall(DMRestoreLocalVector(dm, &localX)); 1540 PetscCall(PetscFree6(funcVal,interpolant,coords,fegeom.detJ,fegeom.J,fegeom.invJ)); 1541 PetscCall(ierr); 1542 } 1543 if (transform) PetscCall(DMPlexBasisTransformApply_Internal(dm, &coords[dE*q], PETSC_FALSE, Nc, funcVal, funcVal, dm->transformCtx)); 1544 /* Call once for each face, except for lagrange field */ 1545 if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolate_Static((PetscFE) obj, &x[fOff], &qgeom, q, interpolant)); 1546 else if (id == PETSCFV_CLASSID) PetscCall(PetscFVInterpolate_Static((PetscFV) obj, &x[fOff], q, interpolant)); 1547 else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", fields[f]); 1548 for (fc = 0; fc < Nc; ++fc) { 1549 const PetscReal wt = quadWeights[q*qNc+(qNc == 1 ? 0 : qc+fc)]; 1550 if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, " cell %D field %D,%D 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]))); 1551 elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc]))*wt*fegeom.detJ[q]; 1552 } 1553 } 1554 fOff += Nb; 1555 qc += Nc; 1556 localDiff[fields[f]] += elemDiff; 1557 if (debug) PetscCall(PetscPrintf(PETSC_COMM_SELF, " cell %D field %D cum diff %g\n", cell, fields[f], (double)localDiff[fields[f]])); 1558 } 1559 PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, cell, NULL, &x)); 1560 } 1561 if (label) { 1562 PetscCall(ISRestoreIndices(pointIS, &points)); 1563 PetscCall(ISDestroy(&pointIS)); 1564 } 1565 PetscCall(ISRestoreIndices(fieldIS, &fields)); 1566 PetscCall(PetscFree6(funcVal, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 1567 } 1568 PetscCall(DMRestoreLocalVector(dm, &localX)); 1569 PetscCall(MPIU_Allreduce(localDiff, diff, Nf, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm))); 1570 PetscCall(PetscFree(localDiff)); 1571 for (f = 0; f < Nf; ++f) diff[f] = PetscSqrtReal(diff[f]); 1572 PetscFunctionReturn(0); 1573 } 1574 1575 /*@C 1576 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. 1577 1578 Collective on dm 1579 1580 Input Parameters: 1581 + dm - The DM 1582 . time - The time 1583 . funcs - The functions to evaluate for each field component: NULL means that component does not contribute to error calculation 1584 . ctxs - Optional array of contexts to pass to each function, or NULL. 1585 - X - The coefficient vector u_h 1586 1587 Output Parameter: 1588 . D - A Vec which holds the difference ||u - u_h||_2 for each cell 1589 1590 Level: developer 1591 1592 .seealso: DMProjectFunction(), DMComputeL2Diff(), DMPlexComputeL2FieldDiff(), DMComputeL2GradientDiff() 1593 @*/ 1594 PetscErrorCode DMPlexComputeL2DiffVec(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, Vec D) 1595 { 1596 PetscSection section; 1597 PetscQuadrature quad; 1598 Vec localX; 1599 PetscFEGeom fegeom; 1600 PetscScalar *funcVal, *interpolant; 1601 PetscReal *coords; 1602 const PetscReal *quadPoints, *quadWeights; 1603 PetscInt dim, coordDim, numFields, numComponents = 0, qNc, Nq, cStart, cEnd, c, field, fieldOffset; 1604 1605 PetscFunctionBegin; 1606 PetscCall(VecSet(D, 0.0)); 1607 PetscCall(DMGetDimension(dm, &dim)); 1608 PetscCall(DMGetCoordinateDim(dm, &coordDim)); 1609 PetscCall(DMGetLocalSection(dm, §ion)); 1610 PetscCall(PetscSectionGetNumFields(section, &numFields)); 1611 PetscCall(DMGetLocalVector(dm, &localX)); 1612 PetscCall(DMProjectFunctionLocal(dm, time, funcs, ctxs, INSERT_BC_VALUES, localX)); 1613 PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX)); 1614 PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX)); 1615 for (field = 0; field < numFields; ++field) { 1616 PetscObject obj; 1617 PetscClassId id; 1618 PetscInt Nc; 1619 1620 PetscCall(DMGetField(dm, field, NULL, &obj)); 1621 PetscCall(PetscObjectGetClassId(obj, &id)); 1622 if (id == PETSCFE_CLASSID) { 1623 PetscFE fe = (PetscFE) obj; 1624 1625 PetscCall(PetscFEGetQuadrature(fe, &quad)); 1626 PetscCall(PetscFEGetNumComponents(fe, &Nc)); 1627 } else if (id == PETSCFV_CLASSID) { 1628 PetscFV fv = (PetscFV) obj; 1629 1630 PetscCall(PetscFVGetQuadrature(fv, &quad)); 1631 PetscCall(PetscFVGetNumComponents(fv, &Nc)); 1632 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", field); 1633 numComponents += Nc; 1634 } 1635 PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights)); 1636 PetscCheck(!(qNc != 1) || !(qNc != numComponents),PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_SIZ, "Quadrature components %D != %D field components", qNc, numComponents); 1637 PetscCall(PetscMalloc6(numComponents,&funcVal,numComponents,&interpolant,coordDim*Nq,&coords,Nq,&fegeom.detJ,coordDim*coordDim*Nq,&fegeom.J,coordDim*coordDim*Nq,&fegeom.invJ)); 1638 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 1639 for (c = cStart; c < cEnd; ++c) { 1640 PetscScalar *x = NULL; 1641 PetscScalar elemDiff = 0.0; 1642 PetscInt qc = 0; 1643 1644 PetscCall(DMPlexComputeCellGeometryFEM(dm, c, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 1645 PetscCall(DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x)); 1646 1647 for (field = 0, fieldOffset = 0; field < numFields; ++field) { 1648 PetscObject obj; 1649 PetscClassId id; 1650 void * const ctx = ctxs ? ctxs[field] : NULL; 1651 PetscInt Nb, Nc, q, fc; 1652 1653 PetscCall(DMGetField(dm, field, NULL, &obj)); 1654 PetscCall(PetscObjectGetClassId(obj, &id)); 1655 if (id == PETSCFE_CLASSID) {PetscCall(PetscFEGetNumComponents((PetscFE) obj, &Nc));PetscCall(PetscFEGetDimension((PetscFE) obj, &Nb));} 1656 else if (id == PETSCFV_CLASSID) {PetscCall(PetscFVGetNumComponents((PetscFV) obj, &Nc));Nb = 1;} 1657 else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", field); 1658 if (funcs[field]) { 1659 for (q = 0; q < Nq; ++q) { 1660 PetscFEGeom qgeom; 1661 1662 qgeom.dimEmbed = fegeom.dimEmbed; 1663 qgeom.J = &fegeom.J[q*coordDim*coordDim]; 1664 qgeom.invJ = &fegeom.invJ[q*coordDim*coordDim]; 1665 qgeom.detJ = &fegeom.detJ[q]; 1666 PetscCheck(fegeom.detJ[q] > 0.0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %D, quadrature points %D", (double)fegeom.detJ[q], c, q); 1667 PetscCall((*funcs[field])(coordDim, time, &coords[q*coordDim], Nc, funcVal, ctx)); 1668 #if defined(needs_fix_with_return_code_argument) 1669 if (ierr) { 1670 PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x)); 1671 PetscCall(PetscFree6(funcVal,interpolant,coords,fegeom.detJ,fegeom.J,fegeom.invJ)); 1672 PetscCall(DMRestoreLocalVector(dm, &localX)); 1673 } 1674 #endif 1675 if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolate_Static((PetscFE) obj, &x[fieldOffset], &qgeom, q, interpolant)); 1676 else if (id == PETSCFV_CLASSID) PetscCall(PetscFVInterpolate_Static((PetscFV) obj, &x[fieldOffset], q, interpolant)); 1677 else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", field); 1678 for (fc = 0; fc < Nc; ++fc) { 1679 const PetscReal wt = quadWeights[q*qNc+(qNc == 1 ? 0 : qc+fc)]; 1680 elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc]))*wt*fegeom.detJ[q]; 1681 } 1682 } 1683 } 1684 fieldOffset += Nb; 1685 qc += Nc; 1686 } 1687 PetscCall(DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x)); 1688 PetscCall(VecSetValue(D, c - cStart, elemDiff, INSERT_VALUES)); 1689 } 1690 PetscCall(PetscFree6(funcVal,interpolant,coords,fegeom.detJ,fegeom.J,fegeom.invJ)); 1691 PetscCall(DMRestoreLocalVector(dm, &localX)); 1692 PetscCall(VecSqrtAbs(D)); 1693 PetscFunctionReturn(0); 1694 } 1695 1696 /*@ 1697 DMPlexComputeClementInterpolant - This function computes the L2 projection of the cellwise values of a function u onto P1, and stores it in a Vec. 1698 1699 Collective on dm 1700 1701 Input Parameters: 1702 + dm - The DM 1703 - locX - The coefficient vector u_h 1704 1705 Output Parameter: 1706 . locC - A Vec which holds the Clement interpolant of the function 1707 1708 Notes: 1709 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 1710 1711 Level: developer 1712 1713 .seealso: DMProjectFunction(), DMComputeL2Diff(), DMPlexComputeL2FieldDiff(), DMComputeL2GradientDiff() 1714 @*/ 1715 PetscErrorCode DMPlexComputeClementInterpolant(DM dm, Vec locX, Vec locC) 1716 { 1717 PetscInt debug = ((DM_Plex *) dm->data)->printFEM; 1718 DM dmc; 1719 PetscQuadrature quad; 1720 PetscScalar *interpolant, *valsum; 1721 PetscFEGeom fegeom; 1722 PetscReal *coords; 1723 const PetscReal *quadPoints, *quadWeights; 1724 PetscInt dim, cdim, Nf, f, Nc = 0, Nq, qNc, cStart, cEnd, vStart, vEnd, v; 1725 1726 PetscFunctionBegin; 1727 PetscCall(PetscCitationsRegister(ClementCitation, &Clementcite)); 1728 PetscCall(VecGetDM(locC, &dmc)); 1729 PetscCall(VecSet(locC, 0.0)); 1730 PetscCall(DMGetDimension(dm, &dim)); 1731 PetscCall(DMGetCoordinateDim(dm, &cdim)); 1732 fegeom.dimEmbed = cdim; 1733 PetscCall(DMGetNumFields(dm, &Nf)); 1734 PetscCheck(Nf > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fields is zero!"); 1735 for (f = 0; f < Nf; ++f) { 1736 PetscObject obj; 1737 PetscClassId id; 1738 PetscInt fNc; 1739 1740 PetscCall(DMGetField(dm, f, NULL, &obj)); 1741 PetscCall(PetscObjectGetClassId(obj, &id)); 1742 if (id == PETSCFE_CLASSID) { 1743 PetscFE fe = (PetscFE) obj; 1744 1745 PetscCall(PetscFEGetQuadrature(fe, &quad)); 1746 PetscCall(PetscFEGetNumComponents(fe, &fNc)); 1747 } else if (id == PETSCFV_CLASSID) { 1748 PetscFV fv = (PetscFV) obj; 1749 1750 PetscCall(PetscFVGetQuadrature(fv, &quad)); 1751 PetscCall(PetscFVGetNumComponents(fv, &fNc)); 1752 } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", f); 1753 Nc += fNc; 1754 } 1755 PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights)); 1756 PetscCheck(qNc == 1,PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_SIZ, "Quadrature components %D > 1", qNc); 1757 PetscCall(PetscMalloc6(Nc*2, &valsum, Nc, &interpolant, cdim*Nq, &coords, Nq, &fegeom.detJ, cdim*cdim*Nq, &fegeom.J, cdim*cdim*Nq, &fegeom.invJ)); 1758 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1759 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 1760 for (v = vStart; v < vEnd; ++v) { 1761 PetscScalar volsum = 0.0; 1762 PetscInt *star = NULL; 1763 PetscInt starSize, st, fc; 1764 1765 PetscCall(PetscArrayzero(valsum, Nc)); 1766 PetscCall(DMPlexGetTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star)); 1767 for (st = 0; st < starSize*2; st += 2) { 1768 const PetscInt cell = star[st]; 1769 PetscScalar *val = &valsum[Nc]; 1770 PetscScalar *x = NULL; 1771 PetscReal vol = 0.0; 1772 PetscInt foff = 0; 1773 1774 if ((cell < cStart) || (cell >= cEnd)) continue; 1775 PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 1776 PetscCall(DMPlexVecGetClosure(dm, NULL, locX, cell, NULL, &x)); 1777 for (f = 0; f < Nf; ++f) { 1778 PetscObject obj; 1779 PetscClassId id; 1780 PetscInt Nb, fNc, q; 1781 1782 PetscCall(PetscArrayzero(val, Nc)); 1783 PetscCall(DMGetField(dm, f, NULL, &obj)); 1784 PetscCall(PetscObjectGetClassId(obj, &id)); 1785 if (id == PETSCFE_CLASSID) {PetscCall(PetscFEGetNumComponents((PetscFE) obj, &fNc));PetscCall(PetscFEGetDimension((PetscFE) obj, &Nb));} 1786 else if (id == PETSCFV_CLASSID) {PetscCall(PetscFVGetNumComponents((PetscFV) obj, &fNc));Nb = 1;} 1787 else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", f); 1788 for (q = 0; q < Nq; ++q) { 1789 const PetscReal wt = quadWeights[q]*fegeom.detJ[q]; 1790 PetscFEGeom qgeom; 1791 1792 qgeom.dimEmbed = fegeom.dimEmbed; 1793 qgeom.J = &fegeom.J[q*cdim*cdim]; 1794 qgeom.invJ = &fegeom.invJ[q*cdim*cdim]; 1795 qgeom.detJ = &fegeom.detJ[q]; 1796 PetscCheck(fegeom.detJ[q] > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %D, quadrature points %D", (double) fegeom.detJ[q], cell, q); 1797 if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolate_Static((PetscFE) obj, &x[foff], &qgeom, q, interpolant)); 1798 else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", f); 1799 for (fc = 0; fc < fNc; ++fc) val[foff+fc] += interpolant[fc]*wt; 1800 vol += wt; 1801 } 1802 foff += Nb; 1803 } 1804 PetscCall(DMPlexVecRestoreClosure(dm, NULL, locX, cell, NULL, &x)); 1805 for (fc = 0; fc < Nc; ++fc) valsum[fc] += val[fc]; 1806 volsum += vol; 1807 if (debug) { 1808 PetscCall(PetscPrintf(PETSC_COMM_SELF, "Vertex %" PetscInt_FMT " Cell %" PetscInt_FMT " value: [", v, cell)); 1809 for (fc = 0; fc < Nc; ++fc) { 1810 if (fc) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", ")); 1811 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g", (double) PetscRealPart(val[fc]))); 1812 } 1813 PetscCall(PetscPrintf(PETSC_COMM_SELF, "]\n")); 1814 } 1815 } 1816 for (fc = 0; fc < Nc; ++fc) valsum[fc] /= volsum; 1817 PetscCall(DMPlexRestoreTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star)); 1818 PetscCall(DMPlexVecSetClosure(dmc, NULL, locC, v, valsum, INSERT_VALUES)); 1819 } 1820 PetscCall(PetscFree6(valsum, interpolant, coords, fegeom.detJ, fegeom.J, fegeom.invJ)); 1821 PetscFunctionReturn(0); 1822 } 1823 1824 /*@ 1825 DMPlexComputeGradientClementInterpolant - This function computes the L2 projection of the cellwise gradient of a function u onto P1, and stores it in a Vec. 1826 1827 Collective on dm 1828 1829 Input Parameters: 1830 + dm - The DM 1831 - locX - The coefficient vector u_h 1832 1833 Output Parameter: 1834 . locC - A Vec which holds the Clement interpolant of the gradient 1835 1836 Notes: 1837 \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 1838 1839 Level: developer 1840 1841 .seealso: DMProjectFunction(), DMComputeL2Diff(), DMPlexComputeL2FieldDiff(), DMComputeL2GradientDiff() 1842 @*/ 1843 PetscErrorCode DMPlexComputeGradientClementInterpolant(DM dm, Vec locX, Vec locC) 1844 { 1845 DM_Plex *mesh = (DM_Plex *) dm->data; 1846 PetscInt debug = mesh->printFEM; 1847 DM dmC; 1848 PetscQuadrature quad; 1849 PetscScalar *interpolant, *gradsum; 1850 PetscFEGeom fegeom; 1851 PetscReal *coords; 1852 const PetscReal *quadPoints, *quadWeights; 1853 PetscInt dim, coordDim, numFields, numComponents = 0, qNc, Nq, cStart, cEnd, vStart, vEnd, v, field, fieldOffset; 1854 1855 PetscFunctionBegin; 1856 PetscCall(PetscCitationsRegister(ClementCitation, &Clementcite)); 1857 PetscCall(VecGetDM(locC, &dmC)); 1858 PetscCall(VecSet(locC, 0.0)); 1859 PetscCall(DMGetDimension(dm, &dim)); 1860 PetscCall(DMGetCoordinateDim(dm, &coordDim)); 1861 fegeom.dimEmbed = coordDim; 1862 PetscCall(DMGetNumFields(dm, &numFields)); 1863 PetscCheck(numFields,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fields is zero!"); 1864 for (field = 0; field < numFields; ++field) { 1865 PetscObject obj; 1866 PetscClassId id; 1867 PetscInt Nc; 1868 1869 PetscCall(DMGetField(dm, field, NULL, &obj)); 1870 PetscCall(PetscObjectGetClassId(obj, &id)); 1871 if (id == PETSCFE_CLASSID) { 1872 PetscFE fe = (PetscFE) obj; 1873 1874 PetscCall(PetscFEGetQuadrature(fe, &quad)); 1875 PetscCall(PetscFEGetNumComponents(fe, &Nc)); 1876 } else if (id == PETSCFV_CLASSID) { 1877 PetscFV fv = (PetscFV) obj; 1878 1879 PetscCall(PetscFVGetQuadrature(fv, &quad)); 1880 PetscCall(PetscFVGetNumComponents(fv, &Nc)); 1881 } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", field); 1882 numComponents += Nc; 1883 } 1884 PetscCall(PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights)); 1885 PetscCheck(!(qNc != 1) || !(qNc != numComponents),PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_SIZ, "Quadrature components %D != %D field components", qNc, numComponents); 1886 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)); 1887 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 1888 PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd)); 1889 for (v = vStart; v < vEnd; ++v) { 1890 PetscScalar volsum = 0.0; 1891 PetscInt *star = NULL; 1892 PetscInt starSize, st, d, fc; 1893 1894 PetscCall(PetscArrayzero(gradsum, coordDim*numComponents)); 1895 PetscCall(DMPlexGetTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star)); 1896 for (st = 0; st < starSize*2; st += 2) { 1897 const PetscInt cell = star[st]; 1898 PetscScalar *grad = &gradsum[coordDim*numComponents]; 1899 PetscScalar *x = NULL; 1900 PetscReal vol = 0.0; 1901 1902 if ((cell < cStart) || (cell >= cEnd)) continue; 1903 PetscCall(DMPlexComputeCellGeometryFEM(dm, cell, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ)); 1904 PetscCall(DMPlexVecGetClosure(dm, NULL, locX, cell, NULL, &x)); 1905 for (field = 0, fieldOffset = 0; field < numFields; ++field) { 1906 PetscObject obj; 1907 PetscClassId id; 1908 PetscInt Nb, Nc, q, qc = 0; 1909 1910 PetscCall(PetscArrayzero(grad, coordDim*numComponents)); 1911 PetscCall(DMGetField(dm, field, NULL, &obj)); 1912 PetscCall(PetscObjectGetClassId(obj, &id)); 1913 if (id == PETSCFE_CLASSID) {PetscCall(PetscFEGetNumComponents((PetscFE) obj, &Nc));PetscCall(PetscFEGetDimension((PetscFE) obj, &Nb));} 1914 else if (id == PETSCFV_CLASSID) {PetscCall(PetscFVGetNumComponents((PetscFV) obj, &Nc));Nb = 1;} 1915 else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", field); 1916 for (q = 0; q < Nq; ++q) { 1917 PetscFEGeom qgeom; 1918 1919 qgeom.dimEmbed = fegeom.dimEmbed; 1920 qgeom.J = &fegeom.J[q*coordDim*coordDim]; 1921 qgeom.invJ = &fegeom.invJ[q*coordDim*coordDim]; 1922 qgeom.detJ = &fegeom.detJ[q]; 1923 PetscCheck(fegeom.detJ[q] > 0.0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %D, quadrature points %D", (double)fegeom.detJ[q], cell, q); 1924 if (id == PETSCFE_CLASSID) PetscCall(PetscFEInterpolateGradient_Static((PetscFE) obj, 1, &x[fieldOffset], &qgeom, q, interpolant)); 1925 else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", field); 1926 for (fc = 0; fc < Nc; ++fc) { 1927 const PetscReal wt = quadWeights[q*qNc+qc]; 1928 1929 for (d = 0; d < coordDim; ++d) grad[fc*coordDim+d] += interpolant[fc*dim+d]*wt*fegeom.detJ[q]; 1930 } 1931 vol += quadWeights[q*qNc]*fegeom.detJ[q]; 1932 } 1933 fieldOffset += Nb; 1934 qc += Nc; 1935 } 1936 PetscCall(DMPlexVecRestoreClosure(dm, NULL, locX, cell, NULL, &x)); 1937 for (fc = 0; fc < numComponents; ++fc) { 1938 for (d = 0; d < coordDim; ++d) { 1939 gradsum[fc*coordDim+d] += grad[fc*coordDim+d]; 1940 } 1941 } 1942 volsum += vol; 1943 if (debug) { 1944 PetscCall(PetscPrintf(PETSC_COMM_SELF, "Vertex %" PetscInt_FMT " Cell %" PetscInt_FMT " gradient: [", v, cell)); 1945 for (fc = 0; fc < numComponents; ++fc) { 1946 for (d = 0; d < coordDim; ++d) { 1947 if (fc || d > 0) PetscCall(PetscPrintf(PETSC_COMM_SELF, ", ")); 1948 PetscCall(PetscPrintf(PETSC_COMM_SELF, "%g", (double)PetscRealPart(grad[fc*coordDim+d]))); 1949 } 1950 } 1951 PetscCall(PetscPrintf(PETSC_COMM_SELF, "]\n")); 1952 } 1953 } 1954 for (fc = 0; fc < numComponents; ++fc) { 1955 for (d = 0; d < coordDim; ++d) gradsum[fc*coordDim+d] /= volsum; 1956 } 1957 PetscCall(DMPlexRestoreTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star)); 1958 PetscCall(DMPlexVecSetClosure(dmC, NULL, locC, v, gradsum, INSERT_VALUES)); 1959 } 1960 PetscCall(PetscFree6(gradsum,interpolant,coords,fegeom.detJ,fegeom.J,fegeom.invJ)); 1961 PetscFunctionReturn(0); 1962 } 1963 1964 static PetscErrorCode DMPlexComputeIntegral_Internal(DM dm, Vec X, PetscInt cStart, PetscInt cEnd, PetscScalar *cintegral, void *user) 1965 { 1966 DM dmAux = NULL; 1967 PetscDS prob, probAux = NULL; 1968 PetscSection section, sectionAux; 1969 Vec locX, locA; 1970 PetscInt dim, numCells = cEnd - cStart, c, f; 1971 PetscBool useFVM = PETSC_FALSE; 1972 /* DS */ 1973 PetscInt Nf, totDim, *uOff, *uOff_x, numConstants; 1974 PetscInt NfAux, totDimAux, *aOff; 1975 PetscScalar *u, *a; 1976 const PetscScalar *constants; 1977 /* Geometry */ 1978 PetscFEGeom *cgeomFEM; 1979 DM dmGrad; 1980 PetscQuadrature affineQuad = NULL; 1981 Vec cellGeometryFVM = NULL, faceGeometryFVM = NULL, locGrad = NULL; 1982 PetscFVCellGeom *cgeomFVM; 1983 const PetscScalar *lgrad; 1984 PetscInt maxDegree; 1985 DMField coordField; 1986 IS cellIS; 1987 1988 PetscFunctionBegin; 1989 PetscCall(DMGetDS(dm, &prob)); 1990 PetscCall(DMGetDimension(dm, &dim)); 1991 PetscCall(DMGetLocalSection(dm, §ion)); 1992 PetscCall(DMGetNumFields(dm, &Nf)); 1993 /* Determine which discretizations we have */ 1994 for (f = 0; f < Nf; ++f) { 1995 PetscObject obj; 1996 PetscClassId id; 1997 1998 PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 1999 PetscCall(PetscObjectGetClassId(obj, &id)); 2000 if (id == PETSCFV_CLASSID) useFVM = PETSC_TRUE; 2001 } 2002 /* Get local solution with boundary values */ 2003 PetscCall(DMGetLocalVector(dm, &locX)); 2004 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locX, 0.0, NULL, NULL, NULL)); 2005 PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, locX)); 2006 PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, locX)); 2007 /* Read DS information */ 2008 PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 2009 PetscCall(PetscDSGetComponentOffsets(prob, &uOff)); 2010 PetscCall(PetscDSGetComponentDerivativeOffsets(prob, &uOff_x)); 2011 PetscCall(ISCreateStride(PETSC_COMM_SELF,numCells,cStart,1,&cellIS)); 2012 PetscCall(PetscDSGetConstants(prob, &numConstants, &constants)); 2013 /* Read Auxiliary DS information */ 2014 PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &locA)); 2015 if (locA) { 2016 PetscCall(VecGetDM(locA, &dmAux)); 2017 PetscCall(DMGetDS(dmAux, &probAux)); 2018 PetscCall(PetscDSGetNumFields(probAux, &NfAux)); 2019 PetscCall(DMGetLocalSection(dmAux, §ionAux)); 2020 PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 2021 PetscCall(PetscDSGetComponentOffsets(probAux, &aOff)); 2022 } 2023 /* Allocate data arrays */ 2024 PetscCall(PetscCalloc1(numCells*totDim, &u)); 2025 if (dmAux) PetscCall(PetscMalloc1(numCells*totDimAux, &a)); 2026 /* Read out geometry */ 2027 PetscCall(DMGetCoordinateField(dm,&coordField)); 2028 PetscCall(DMFieldGetDegree(coordField,cellIS,NULL,&maxDegree)); 2029 if (maxDegree <= 1) { 2030 PetscCall(DMFieldCreateDefaultQuadrature(coordField,cellIS,&affineQuad)); 2031 if (affineQuad) { 2032 PetscCall(DMFieldCreateFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&cgeomFEM)); 2033 } 2034 } 2035 if (useFVM) { 2036 PetscFV fv = NULL; 2037 Vec grad; 2038 PetscInt fStart, fEnd; 2039 PetscBool compGrad; 2040 2041 for (f = 0; f < Nf; ++f) { 2042 PetscObject obj; 2043 PetscClassId id; 2044 2045 PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 2046 PetscCall(PetscObjectGetClassId(obj, &id)); 2047 if (id == PETSCFV_CLASSID) {fv = (PetscFV) obj; break;} 2048 } 2049 PetscCall(PetscFVGetComputeGradients(fv, &compGrad)); 2050 PetscCall(PetscFVSetComputeGradients(fv, PETSC_TRUE)); 2051 PetscCall(DMPlexComputeGeometryFVM(dm, &cellGeometryFVM, &faceGeometryFVM)); 2052 PetscCall(DMPlexComputeGradientFVM(dm, fv, faceGeometryFVM, cellGeometryFVM, &dmGrad)); 2053 PetscCall(PetscFVSetComputeGradients(fv, compGrad)); 2054 PetscCall(VecGetArrayRead(cellGeometryFVM, (const PetscScalar **) &cgeomFVM)); 2055 /* Reconstruct and limit cell gradients */ 2056 PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 2057 PetscCall(DMGetGlobalVector(dmGrad, &grad)); 2058 PetscCall(DMPlexReconstructGradients_Internal(dm, fv, fStart, fEnd, faceGeometryFVM, cellGeometryFVM, locX, grad)); 2059 /* Communicate gradient values */ 2060 PetscCall(DMGetLocalVector(dmGrad, &locGrad)); 2061 PetscCall(DMGlobalToLocalBegin(dmGrad, grad, INSERT_VALUES, locGrad)); 2062 PetscCall(DMGlobalToLocalEnd(dmGrad, grad, INSERT_VALUES, locGrad)); 2063 PetscCall(DMRestoreGlobalVector(dmGrad, &grad)); 2064 /* Handle non-essential (e.g. outflow) boundary values */ 2065 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_FALSE, locX, 0.0, faceGeometryFVM, cellGeometryFVM, locGrad)); 2066 PetscCall(VecGetArrayRead(locGrad, &lgrad)); 2067 } 2068 /* Read out data from inputs */ 2069 for (c = cStart; c < cEnd; ++c) { 2070 PetscScalar *x = NULL; 2071 PetscInt i; 2072 2073 PetscCall(DMPlexVecGetClosure(dm, section, locX, c, NULL, &x)); 2074 for (i = 0; i < totDim; ++i) u[c*totDim+i] = x[i]; 2075 PetscCall(DMPlexVecRestoreClosure(dm, section, locX, c, NULL, &x)); 2076 if (dmAux) { 2077 PetscCall(DMPlexVecGetClosure(dmAux, sectionAux, locA, c, NULL, &x)); 2078 for (i = 0; i < totDimAux; ++i) a[c*totDimAux+i] = x[i]; 2079 PetscCall(DMPlexVecRestoreClosure(dmAux, sectionAux, locA, c, NULL, &x)); 2080 } 2081 } 2082 /* Do integration for each field */ 2083 for (f = 0; f < Nf; ++f) { 2084 PetscObject obj; 2085 PetscClassId id; 2086 PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset; 2087 2088 PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 2089 PetscCall(PetscObjectGetClassId(obj, &id)); 2090 if (id == PETSCFE_CLASSID) { 2091 PetscFE fe = (PetscFE) obj; 2092 PetscQuadrature q; 2093 PetscFEGeom *chunkGeom = NULL; 2094 PetscInt Nq, Nb; 2095 2096 PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 2097 PetscCall(PetscFEGetQuadrature(fe, &q)); 2098 PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Nq, NULL, NULL)); 2099 PetscCall(PetscFEGetDimension(fe, &Nb)); 2100 blockSize = Nb*Nq; 2101 batchSize = numBlocks * blockSize; 2102 PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 2103 numChunks = numCells / (numBatches*batchSize); 2104 Ne = numChunks*numBatches*batchSize; 2105 Nr = numCells % (numBatches*batchSize); 2106 offset = numCells - Nr; 2107 if (!affineQuad) { 2108 PetscCall(DMFieldCreateFEGeom(coordField,cellIS,q,PETSC_FALSE,&cgeomFEM)); 2109 } 2110 PetscCall(PetscFEGeomGetChunk(cgeomFEM,0,offset,&chunkGeom)); 2111 PetscCall(PetscFEIntegrate(prob, f, Ne, chunkGeom, u, probAux, a, cintegral)); 2112 PetscCall(PetscFEGeomGetChunk(cgeomFEM,offset,numCells,&chunkGeom)); 2113 PetscCall(PetscFEIntegrate(prob, f, Nr, chunkGeom, &u[offset*totDim], probAux, &a[offset*totDimAux], &cintegral[offset*Nf])); 2114 PetscCall(PetscFEGeomRestoreChunk(cgeomFEM,offset,numCells,&chunkGeom)); 2115 if (!affineQuad) { 2116 PetscCall(PetscFEGeomDestroy(&cgeomFEM)); 2117 } 2118 } else if (id == PETSCFV_CLASSID) { 2119 PetscInt foff; 2120 PetscPointFunc obj_func; 2121 PetscScalar lint; 2122 2123 PetscCall(PetscDSGetObjective(prob, f, &obj_func)); 2124 PetscCall(PetscDSGetFieldOffset(prob, f, &foff)); 2125 if (obj_func) { 2126 for (c = 0; c < numCells; ++c) { 2127 PetscScalar *u_x; 2128 2129 PetscCall(DMPlexPointLocalRead(dmGrad, c, lgrad, &u_x)); 2130 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); 2131 cintegral[c*Nf+f] += PetscRealPart(lint)*cgeomFVM[c].volume; 2132 } 2133 } 2134 } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", f); 2135 } 2136 /* Cleanup data arrays */ 2137 if (useFVM) { 2138 PetscCall(VecRestoreArrayRead(locGrad, &lgrad)); 2139 PetscCall(VecRestoreArrayRead(cellGeometryFVM, (const PetscScalar **) &cgeomFVM)); 2140 PetscCall(DMRestoreLocalVector(dmGrad, &locGrad)); 2141 PetscCall(VecDestroy(&faceGeometryFVM)); 2142 PetscCall(VecDestroy(&cellGeometryFVM)); 2143 PetscCall(DMDestroy(&dmGrad)); 2144 } 2145 if (dmAux) PetscCall(PetscFree(a)); 2146 PetscCall(PetscFree(u)); 2147 /* Cleanup */ 2148 if (affineQuad) { 2149 PetscCall(PetscFEGeomDestroy(&cgeomFEM)); 2150 } 2151 PetscCall(PetscQuadratureDestroy(&affineQuad)); 2152 PetscCall(ISDestroy(&cellIS)); 2153 PetscCall(DMRestoreLocalVector(dm, &locX)); 2154 PetscFunctionReturn(0); 2155 } 2156 2157 /*@ 2158 DMPlexComputeIntegralFEM - Form the integral over the domain from the global input X using pointwise functions specified by the user 2159 2160 Input Parameters: 2161 + dm - The mesh 2162 . X - Global input vector 2163 - user - The user context 2164 2165 Output Parameter: 2166 . integral - Integral for each field 2167 2168 Level: developer 2169 2170 .seealso: DMPlexSNESComputeResidualFEM() 2171 @*/ 2172 PetscErrorCode DMPlexComputeIntegralFEM(DM dm, Vec X, PetscScalar *integral, void *user) 2173 { 2174 DM_Plex *mesh = (DM_Plex *) dm->data; 2175 PetscScalar *cintegral, *lintegral; 2176 PetscInt Nf, f, cellHeight, cStart, cEnd, cell; 2177 2178 PetscFunctionBegin; 2179 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2180 PetscValidHeaderSpecific(X, VEC_CLASSID, 2); 2181 PetscValidScalarPointer(integral, 3); 2182 PetscCall(PetscLogEventBegin(DMPLEX_IntegralFEM,dm,0,0,0)); 2183 PetscCall(DMGetNumFields(dm, &Nf)); 2184 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 2185 PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 2186 /* TODO Introduce a loop over large chunks (right now this is a single chunk) */ 2187 PetscCall(PetscCalloc2(Nf, &lintegral, (cEnd-cStart)*Nf, &cintegral)); 2188 PetscCall(DMPlexComputeIntegral_Internal(dm, X, cStart, cEnd, cintegral, user)); 2189 /* Sum up values */ 2190 for (cell = cStart; cell < cEnd; ++cell) { 2191 const PetscInt c = cell - cStart; 2192 2193 if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, "Cell Integral", Nf, &cintegral[c*Nf])); 2194 for (f = 0; f < Nf; ++f) lintegral[f] += cintegral[c*Nf+f]; 2195 } 2196 PetscCall(MPIU_Allreduce(lintegral, integral, Nf, MPIU_SCALAR, MPIU_SUM, PetscObjectComm((PetscObject) dm))); 2197 if (mesh->printFEM) { 2198 PetscCall(PetscPrintf(PetscObjectComm((PetscObject) dm), "Integral:")); 2199 for (f = 0; f < Nf; ++f) PetscCall(PetscPrintf(PetscObjectComm((PetscObject) dm), " %g", (double) PetscRealPart(integral[f]))); 2200 PetscCall(PetscPrintf(PetscObjectComm((PetscObject) dm), "\n")); 2201 } 2202 PetscCall(PetscFree2(lintegral, cintegral)); 2203 PetscCall(PetscLogEventEnd(DMPLEX_IntegralFEM,dm,0,0,0)); 2204 PetscFunctionReturn(0); 2205 } 2206 2207 /*@ 2208 DMPlexComputeCellwiseIntegralFEM - Form the vector of cellwise integrals F from the global input X using pointwise functions specified by the user 2209 2210 Input Parameters: 2211 + dm - The mesh 2212 . X - Global input vector 2213 - user - The user context 2214 2215 Output Parameter: 2216 . integral - Cellwise integrals for each field 2217 2218 Level: developer 2219 2220 .seealso: DMPlexSNESComputeResidualFEM() 2221 @*/ 2222 PetscErrorCode DMPlexComputeCellwiseIntegralFEM(DM dm, Vec X, Vec F, void *user) 2223 { 2224 DM_Plex *mesh = (DM_Plex *) dm->data; 2225 DM dmF; 2226 PetscSection sectionF; 2227 PetscScalar *cintegral, *af; 2228 PetscInt Nf, f, cellHeight, cStart, cEnd, cell; 2229 2230 PetscFunctionBegin; 2231 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2232 PetscValidHeaderSpecific(X, VEC_CLASSID, 2); 2233 PetscValidHeaderSpecific(F, VEC_CLASSID, 3); 2234 PetscCall(PetscLogEventBegin(DMPLEX_IntegralFEM,dm,0,0,0)); 2235 PetscCall(DMGetNumFields(dm, &Nf)); 2236 PetscCall(DMPlexGetVTKCellHeight(dm, &cellHeight)); 2237 PetscCall(DMPlexGetSimplexOrBoxCells(dm, cellHeight, &cStart, &cEnd)); 2238 /* TODO Introduce a loop over large chunks (right now this is a single chunk) */ 2239 PetscCall(PetscCalloc1((cEnd-cStart)*Nf, &cintegral)); 2240 PetscCall(DMPlexComputeIntegral_Internal(dm, X, cStart, cEnd, cintegral, user)); 2241 /* Put values in F*/ 2242 PetscCall(VecGetDM(F, &dmF)); 2243 PetscCall(DMGetLocalSection(dmF, §ionF)); 2244 PetscCall(VecGetArray(F, &af)); 2245 for (cell = cStart; cell < cEnd; ++cell) { 2246 const PetscInt c = cell - cStart; 2247 PetscInt dof, off; 2248 2249 if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, "Cell Integral", Nf, &cintegral[c*Nf])); 2250 PetscCall(PetscSectionGetDof(sectionF, cell, &dof)); 2251 PetscCall(PetscSectionGetOffset(sectionF, cell, &off)); 2252 PetscCheck(dof == Nf,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "The number of cell dofs %D != %D", dof, Nf); 2253 for (f = 0; f < Nf; ++f) af[off+f] = cintegral[c*Nf+f]; 2254 } 2255 PetscCall(VecRestoreArray(F, &af)); 2256 PetscCall(PetscFree(cintegral)); 2257 PetscCall(PetscLogEventEnd(DMPLEX_IntegralFEM,dm,0,0,0)); 2258 PetscFunctionReturn(0); 2259 } 2260 2261 static PetscErrorCode DMPlexComputeBdIntegral_Internal(DM dm, Vec locX, IS pointIS, 2262 void (*func)(PetscInt, PetscInt, PetscInt, 2263 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 2264 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 2265 PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), 2266 PetscScalar *fintegral, void *user) 2267 { 2268 DM plex = NULL, plexA = NULL; 2269 DMEnclosureType encAux; 2270 PetscDS prob, probAux = NULL; 2271 PetscSection section, sectionAux = NULL; 2272 Vec locA = NULL; 2273 DMField coordField; 2274 PetscInt Nf, totDim, *uOff, *uOff_x; 2275 PetscInt NfAux = 0, totDimAux = 0, *aOff = NULL; 2276 PetscScalar *u, *a = NULL; 2277 const PetscScalar *constants; 2278 PetscInt numConstants, f; 2279 2280 PetscFunctionBegin; 2281 PetscCall(DMGetCoordinateField(dm, &coordField)); 2282 PetscCall(DMConvert(dm, DMPLEX, &plex)); 2283 PetscCall(DMGetDS(dm, &prob)); 2284 PetscCall(DMGetLocalSection(dm, §ion)); 2285 PetscCall(PetscSectionGetNumFields(section, &Nf)); 2286 /* Determine which discretizations we have */ 2287 for (f = 0; f < Nf; ++f) { 2288 PetscObject obj; 2289 PetscClassId id; 2290 2291 PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 2292 PetscCall(PetscObjectGetClassId(obj, &id)); 2293 PetscCheck(id != PETSCFV_CLASSID,PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Not supported for FVM (field %D)", f); 2294 } 2295 /* Read DS information */ 2296 PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 2297 PetscCall(PetscDSGetComponentOffsets(prob, &uOff)); 2298 PetscCall(PetscDSGetComponentDerivativeOffsets(prob, &uOff_x)); 2299 PetscCall(PetscDSGetConstants(prob, &numConstants, &constants)); 2300 /* Read Auxiliary DS information */ 2301 PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &locA)); 2302 if (locA) { 2303 DM dmAux; 2304 2305 PetscCall(VecGetDM(locA, &dmAux)); 2306 PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 2307 PetscCall(DMConvert(dmAux, DMPLEX, &plexA)); 2308 PetscCall(DMGetDS(dmAux, &probAux)); 2309 PetscCall(PetscDSGetNumFields(probAux, &NfAux)); 2310 PetscCall(DMGetLocalSection(dmAux, §ionAux)); 2311 PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 2312 PetscCall(PetscDSGetComponentOffsets(probAux, &aOff)); 2313 } 2314 /* Integrate over points */ 2315 { 2316 PetscFEGeom *fgeom, *chunkGeom = NULL; 2317 PetscInt maxDegree; 2318 PetscQuadrature qGeom = NULL; 2319 const PetscInt *points; 2320 PetscInt numFaces, face, Nq, field; 2321 PetscInt numChunks, chunkSize, chunk, Nr, offset; 2322 2323 PetscCall(ISGetLocalSize(pointIS, &numFaces)); 2324 PetscCall(ISGetIndices(pointIS, &points)); 2325 PetscCall(PetscCalloc2(numFaces*totDim, &u, locA ? numFaces*totDimAux : 0, &a)); 2326 PetscCall(DMFieldGetDegree(coordField, pointIS, NULL, &maxDegree)); 2327 for (field = 0; field < Nf; ++field) { 2328 PetscFE fe; 2329 2330 PetscCall(PetscDSGetDiscretization(prob, field, (PetscObject *) &fe)); 2331 if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, pointIS, &qGeom)); 2332 if (!qGeom) { 2333 PetscCall(PetscFEGetFaceQuadrature(fe, &qGeom)); 2334 PetscCall(PetscObjectReference((PetscObject) qGeom)); 2335 } 2336 PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL)); 2337 PetscCall(DMPlexGetFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 2338 for (face = 0; face < numFaces; ++face) { 2339 const PetscInt point = points[face], *support; 2340 PetscScalar *x = NULL; 2341 PetscInt i; 2342 2343 PetscCall(DMPlexGetSupport(dm, point, &support)); 2344 PetscCall(DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x)); 2345 for (i = 0; i < totDim; ++i) u[face*totDim+i] = x[i]; 2346 PetscCall(DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x)); 2347 if (locA) { 2348 PetscInt subp; 2349 PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp)); 2350 PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x)); 2351 for (i = 0; i < totDimAux; ++i) a[f*totDimAux+i] = x[i]; 2352 PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x)); 2353 } 2354 } 2355 /* Get blocking */ 2356 { 2357 PetscQuadrature q; 2358 PetscInt numBatches, batchSize, numBlocks, blockSize; 2359 PetscInt Nq, Nb; 2360 2361 PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 2362 PetscCall(PetscFEGetQuadrature(fe, &q)); 2363 PetscCall(PetscQuadratureGetData(q, NULL, NULL, &Nq, NULL, NULL)); 2364 PetscCall(PetscFEGetDimension(fe, &Nb)); 2365 blockSize = Nb*Nq; 2366 batchSize = numBlocks * blockSize; 2367 chunkSize = numBatches*batchSize; 2368 PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 2369 numChunks = numFaces / chunkSize; 2370 Nr = numFaces % chunkSize; 2371 offset = numFaces - Nr; 2372 } 2373 /* Do integration for each field */ 2374 for (chunk = 0; chunk < numChunks; ++chunk) { 2375 PetscCall(PetscFEGeomGetChunk(fgeom, chunk*chunkSize, (chunk+1)*chunkSize, &chunkGeom)); 2376 PetscCall(PetscFEIntegrateBd(prob, field, func, chunkSize, chunkGeom, u, probAux, a, fintegral)); 2377 PetscCall(PetscFEGeomRestoreChunk(fgeom, 0, offset, &chunkGeom)); 2378 } 2379 PetscCall(PetscFEGeomGetChunk(fgeom, offset, numFaces, &chunkGeom)); 2380 PetscCall(PetscFEIntegrateBd(prob, field, func, Nr, chunkGeom, &u[offset*totDim], probAux, a ? &a[offset*totDimAux] : NULL, &fintegral[offset*Nf])); 2381 PetscCall(PetscFEGeomRestoreChunk(fgeom, offset, numFaces, &chunkGeom)); 2382 /* Cleanup data arrays */ 2383 PetscCall(DMPlexRestoreFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom)); 2384 PetscCall(PetscQuadratureDestroy(&qGeom)); 2385 PetscCall(PetscFree2(u, a)); 2386 PetscCall(ISRestoreIndices(pointIS, &points)); 2387 } 2388 } 2389 if (plex) PetscCall(DMDestroy(&plex)); 2390 if (plexA) PetscCall(DMDestroy(&plexA)); 2391 PetscFunctionReturn(0); 2392 } 2393 2394 /*@ 2395 DMPlexComputeBdIntegral - Form the integral over the specified boundary from the global input X using pointwise functions specified by the user 2396 2397 Input Parameters: 2398 + dm - The mesh 2399 . X - Global input vector 2400 . label - The boundary DMLabel 2401 . numVals - The number of label values to use, or PETSC_DETERMINE for all values 2402 . vals - The label values to use, or PETSC_NULL for all values 2403 . func - The function to integrate along the boundary 2404 - user - The user context 2405 2406 Output Parameter: 2407 . integral - Integral for each field 2408 2409 Level: developer 2410 2411 .seealso: DMPlexComputeIntegralFEM(), DMPlexComputeBdResidualFEM() 2412 @*/ 2413 PetscErrorCode DMPlexComputeBdIntegral(DM dm, Vec X, DMLabel label, PetscInt numVals, const PetscInt vals[], 2414 void (*func)(PetscInt, PetscInt, PetscInt, 2415 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 2416 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 2417 PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), 2418 PetscScalar *integral, void *user) 2419 { 2420 Vec locX; 2421 PetscSection section; 2422 DMLabel depthLabel; 2423 IS facetIS; 2424 PetscInt dim, Nf, f, v; 2425 2426 PetscFunctionBegin; 2427 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2428 PetscValidHeaderSpecific(X, VEC_CLASSID, 2); 2429 PetscValidPointer(label, 3); 2430 if (vals) PetscValidIntPointer(vals, 5); 2431 PetscValidScalarPointer(integral, 7); 2432 PetscCall(PetscLogEventBegin(DMPLEX_IntegralFEM,dm,0,0,0)); 2433 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 2434 PetscCall(DMGetDimension(dm, &dim)); 2435 PetscCall(DMLabelGetStratumIS(depthLabel, dim-1, &facetIS)); 2436 PetscCall(DMGetLocalSection(dm, §ion)); 2437 PetscCall(PetscSectionGetNumFields(section, &Nf)); 2438 /* Get local solution with boundary values */ 2439 PetscCall(DMGetLocalVector(dm, &locX)); 2440 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locX, 0.0, NULL, NULL, NULL)); 2441 PetscCall(DMGlobalToLocalBegin(dm, X, INSERT_VALUES, locX)); 2442 PetscCall(DMGlobalToLocalEnd(dm, X, INSERT_VALUES, locX)); 2443 /* Loop over label values */ 2444 PetscCall(PetscArrayzero(integral, Nf)); 2445 for (v = 0; v < numVals; ++v) { 2446 IS pointIS; 2447 PetscInt numFaces, face; 2448 PetscScalar *fintegral; 2449 2450 PetscCall(DMLabelGetStratumIS(label, vals[v], &pointIS)); 2451 if (!pointIS) continue; /* No points with that id on this process */ 2452 { 2453 IS isectIS; 2454 2455 /* TODO: Special cases of ISIntersect where it is quick to check a priori if one is a superset of the other */ 2456 PetscCall(ISIntersect_Caching_Internal(facetIS, pointIS, &isectIS)); 2457 PetscCall(ISDestroy(&pointIS)); 2458 pointIS = isectIS; 2459 } 2460 PetscCall(ISGetLocalSize(pointIS, &numFaces)); 2461 PetscCall(PetscCalloc1(numFaces*Nf, &fintegral)); 2462 PetscCall(DMPlexComputeBdIntegral_Internal(dm, locX, pointIS, func, fintegral, user)); 2463 /* Sum point contributions into integral */ 2464 for (f = 0; f < Nf; ++f) for (face = 0; face < numFaces; ++face) integral[f] += fintegral[face*Nf+f]; 2465 PetscCall(PetscFree(fintegral)); 2466 PetscCall(ISDestroy(&pointIS)); 2467 } 2468 PetscCall(DMRestoreLocalVector(dm, &locX)); 2469 PetscCall(ISDestroy(&facetIS)); 2470 PetscCall(PetscLogEventEnd(DMPLEX_IntegralFEM,dm,0,0,0)); 2471 PetscFunctionReturn(0); 2472 } 2473 2474 /*@ 2475 DMPlexComputeInterpolatorNested - Form the local portion of the interpolation matrix I from the coarse DM to a uniformly refined DM. 2476 2477 Input Parameters: 2478 + dmc - The coarse mesh 2479 . dmf - The fine mesh 2480 . isRefined - Flag indicating regular refinement, rather than the same topology 2481 - user - The user context 2482 2483 Output Parameter: 2484 . In - The interpolation matrix 2485 2486 Level: developer 2487 2488 .seealso: DMPlexComputeInterpolatorGeneral(), DMPlexComputeJacobianFEM() 2489 @*/ 2490 PetscErrorCode DMPlexComputeInterpolatorNested(DM dmc, DM dmf, PetscBool isRefined, Mat In, void *user) 2491 { 2492 DM_Plex *mesh = (DM_Plex *) dmc->data; 2493 const char *name = "Interpolator"; 2494 PetscFE *feRef; 2495 PetscFV *fvRef; 2496 PetscSection fsection, fglobalSection; 2497 PetscSection csection, cglobalSection; 2498 PetscScalar *elemMat; 2499 PetscInt dim, Nf, f, fieldI, fieldJ, offsetI, offsetJ, cStart, cEnd, c; 2500 PetscInt cTotDim=0, rTotDim = 0; 2501 2502 PetscFunctionBegin; 2503 PetscCall(PetscLogEventBegin(DMPLEX_InterpolatorFEM,dmc,dmf,0,0)); 2504 PetscCall(DMGetDimension(dmf, &dim)); 2505 PetscCall(DMGetLocalSection(dmf, &fsection)); 2506 PetscCall(DMGetGlobalSection(dmf, &fglobalSection)); 2507 PetscCall(DMGetLocalSection(dmc, &csection)); 2508 PetscCall(DMGetGlobalSection(dmc, &cglobalSection)); 2509 PetscCall(PetscSectionGetNumFields(fsection, &Nf)); 2510 PetscCall(DMPlexGetSimplexOrBoxCells(dmc, 0, &cStart, &cEnd)); 2511 PetscCall(PetscCalloc2(Nf, &feRef, Nf, &fvRef)); 2512 for (f = 0; f < Nf; ++f) { 2513 PetscObject obj, objc; 2514 PetscClassId id, idc; 2515 PetscInt rNb = 0, Nc = 0, cNb = 0; 2516 2517 PetscCall(DMGetField(dmf, f, NULL, &obj)); 2518 PetscCall(PetscObjectGetClassId(obj, &id)); 2519 if (id == PETSCFE_CLASSID) { 2520 PetscFE fe = (PetscFE) obj; 2521 2522 if (isRefined) { 2523 PetscCall(PetscFERefine(fe, &feRef[f])); 2524 } else { 2525 PetscCall(PetscObjectReference((PetscObject) fe)); 2526 feRef[f] = fe; 2527 } 2528 PetscCall(PetscFEGetDimension(feRef[f], &rNb)); 2529 PetscCall(PetscFEGetNumComponents(fe, &Nc)); 2530 } else if (id == PETSCFV_CLASSID) { 2531 PetscFV fv = (PetscFV) obj; 2532 PetscDualSpace Q; 2533 2534 if (isRefined) { 2535 PetscCall(PetscFVRefine(fv, &fvRef[f])); 2536 } else { 2537 PetscCall(PetscObjectReference((PetscObject) fv)); 2538 fvRef[f] = fv; 2539 } 2540 PetscCall(PetscFVGetDualSpace(fvRef[f], &Q)); 2541 PetscCall(PetscDualSpaceGetDimension(Q, &rNb)); 2542 PetscCall(PetscFVGetDualSpace(fv, &Q)); 2543 PetscCall(PetscFVGetNumComponents(fv, &Nc)); 2544 } 2545 PetscCall(DMGetField(dmc, f, NULL, &objc)); 2546 PetscCall(PetscObjectGetClassId(objc, &idc)); 2547 if (idc == PETSCFE_CLASSID) { 2548 PetscFE fe = (PetscFE) objc; 2549 2550 PetscCall(PetscFEGetDimension(fe, &cNb)); 2551 } else if (id == PETSCFV_CLASSID) { 2552 PetscFV fv = (PetscFV) obj; 2553 PetscDualSpace Q; 2554 2555 PetscCall(PetscFVGetDualSpace(fv, &Q)); 2556 PetscCall(PetscDualSpaceGetDimension(Q, &cNb)); 2557 } 2558 rTotDim += rNb; 2559 cTotDim += cNb; 2560 } 2561 PetscCall(PetscMalloc1(rTotDim*cTotDim,&elemMat)); 2562 PetscCall(PetscArrayzero(elemMat, rTotDim*cTotDim)); 2563 for (fieldI = 0, offsetI = 0; fieldI < Nf; ++fieldI) { 2564 PetscDualSpace Qref; 2565 PetscQuadrature f; 2566 const PetscReal *qpoints, *qweights; 2567 PetscReal *points; 2568 PetscInt npoints = 0, Nc, Np, fpdim, i, k, p, d; 2569 2570 /* Compose points from all dual basis functionals */ 2571 if (feRef[fieldI]) { 2572 PetscCall(PetscFEGetDualSpace(feRef[fieldI], &Qref)); 2573 PetscCall(PetscFEGetNumComponents(feRef[fieldI], &Nc)); 2574 } else { 2575 PetscCall(PetscFVGetDualSpace(fvRef[fieldI], &Qref)); 2576 PetscCall(PetscFVGetNumComponents(fvRef[fieldI], &Nc)); 2577 } 2578 PetscCall(PetscDualSpaceGetDimension(Qref, &fpdim)); 2579 for (i = 0; i < fpdim; ++i) { 2580 PetscCall(PetscDualSpaceGetFunctional(Qref, i, &f)); 2581 PetscCall(PetscQuadratureGetData(f, NULL, NULL, &Np, NULL, NULL)); 2582 npoints += Np; 2583 } 2584 PetscCall(PetscMalloc1(npoints*dim,&points)); 2585 for (i = 0, k = 0; i < fpdim; ++i) { 2586 PetscCall(PetscDualSpaceGetFunctional(Qref, i, &f)); 2587 PetscCall(PetscQuadratureGetData(f, NULL, NULL, &Np, &qpoints, NULL)); 2588 for (p = 0; p < Np; ++p, ++k) for (d = 0; d < dim; ++d) points[k*dim+d] = qpoints[p*dim+d]; 2589 } 2590 2591 for (fieldJ = 0, offsetJ = 0; fieldJ < Nf; ++fieldJ) { 2592 PetscObject obj; 2593 PetscClassId id; 2594 PetscInt NcJ = 0, cpdim = 0, j, qNc; 2595 2596 PetscCall(DMGetField(dmc, fieldJ, NULL, &obj)); 2597 PetscCall(PetscObjectGetClassId(obj, &id)); 2598 if (id == PETSCFE_CLASSID) { 2599 PetscFE fe = (PetscFE) obj; 2600 PetscTabulation T = NULL; 2601 2602 /* Evaluate basis at points */ 2603 PetscCall(PetscFEGetNumComponents(fe, &NcJ)); 2604 PetscCall(PetscFEGetDimension(fe, &cpdim)); 2605 /* For now, fields only interpolate themselves */ 2606 if (fieldI == fieldJ) { 2607 PetscCheck(Nc == NcJ,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of components in fine space field %D does not match coarse field %D", Nc, NcJ); 2608 PetscCall(PetscFECreateTabulation(fe, 1, npoints, points, 0, &T)); 2609 for (i = 0, k = 0; i < fpdim; ++i) { 2610 PetscCall(PetscDualSpaceGetFunctional(Qref, i, &f)); 2611 PetscCall(PetscQuadratureGetData(f, NULL, &qNc, &Np, NULL, &qweights)); 2612 PetscCheck(qNc == NcJ,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of components in quadrature %D does not match coarse field %D", qNc, NcJ); 2613 for (p = 0; p < Np; ++p, ++k) { 2614 for (j = 0; j < cpdim; ++j) { 2615 /* 2616 cTotDim: Total columns in element interpolation matrix, sum of number of dual basis functionals in each field 2617 offsetI, offsetJ: Offsets into the larger element interpolation matrix for different fields 2618 fpdim, i, cpdim, j: Dofs for fine and coarse grids, correspond to dual space basis functionals 2619 qNC, Nc, Ncj, c: Number of components in this field 2620 Np, p: Number of quad points in the fine grid functional i 2621 k: i*Np + p, overall point number for the interpolation 2622 */ 2623 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]; 2624 } 2625 } 2626 } 2627 PetscCall(PetscTabulationDestroy(&T)); 2628 } 2629 } else if (id == PETSCFV_CLASSID) { 2630 PetscFV fv = (PetscFV) obj; 2631 2632 /* Evaluate constant function at points */ 2633 PetscCall(PetscFVGetNumComponents(fv, &NcJ)); 2634 cpdim = 1; 2635 /* For now, fields only interpolate themselves */ 2636 if (fieldI == fieldJ) { 2637 PetscCheck(Nc == NcJ,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of components in fine space field %D does not match coarse field %D", Nc, NcJ); 2638 for (i = 0, k = 0; i < fpdim; ++i) { 2639 PetscCall(PetscDualSpaceGetFunctional(Qref, i, &f)); 2640 PetscCall(PetscQuadratureGetData(f, NULL, &qNc, &Np, NULL, &qweights)); 2641 PetscCheck(qNc == NcJ,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of components in quadrature %D does not match coarse field %D", qNc, NcJ); 2642 for (p = 0; p < Np; ++p, ++k) { 2643 for (j = 0; j < cpdim; ++j) { 2644 for (c = 0; c < Nc; ++c) elemMat[(offsetI + i)*cTotDim + offsetJ + j] += 1.0*qweights[p*qNc+c]; 2645 } 2646 } 2647 } 2648 } 2649 } 2650 offsetJ += cpdim; 2651 } 2652 offsetI += fpdim; 2653 PetscCall(PetscFree(points)); 2654 } 2655 if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(0, name, rTotDim, cTotDim, elemMat)); 2656 /* Preallocate matrix */ 2657 { 2658 Mat preallocator; 2659 PetscScalar *vals; 2660 PetscInt *cellCIndices, *cellFIndices; 2661 PetscInt locRows, locCols, cell; 2662 2663 PetscCall(MatGetLocalSize(In, &locRows, &locCols)); 2664 PetscCall(MatCreate(PetscObjectComm((PetscObject) In), &preallocator)); 2665 PetscCall(MatSetType(preallocator, MATPREALLOCATOR)); 2666 PetscCall(MatSetSizes(preallocator, locRows, locCols, PETSC_DETERMINE, PETSC_DETERMINE)); 2667 PetscCall(MatSetUp(preallocator)); 2668 PetscCall(PetscCalloc3(rTotDim*cTotDim, &vals,cTotDim,&cellCIndices,rTotDim,&cellFIndices)); 2669 for (cell = cStart; cell < cEnd; ++cell) { 2670 if (isRefined) { 2671 PetscCall(DMPlexMatGetClosureIndicesRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, cell, cellCIndices, cellFIndices)); 2672 PetscCall(MatSetValues(preallocator, rTotDim, cellFIndices, cTotDim, cellCIndices, vals, INSERT_VALUES)); 2673 } else { 2674 PetscCall(DMPlexMatSetClosureGeneral(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, preallocator, cell, vals, INSERT_VALUES)); 2675 } 2676 } 2677 PetscCall(PetscFree3(vals,cellCIndices,cellFIndices)); 2678 PetscCall(MatAssemblyBegin(preallocator, MAT_FINAL_ASSEMBLY)); 2679 PetscCall(MatAssemblyEnd(preallocator, MAT_FINAL_ASSEMBLY)); 2680 PetscCall(MatPreallocatorPreallocate(preallocator, PETSC_TRUE, In)); 2681 PetscCall(MatDestroy(&preallocator)); 2682 } 2683 /* Fill matrix */ 2684 PetscCall(MatZeroEntries(In)); 2685 for (c = cStart; c < cEnd; ++c) { 2686 if (isRefined) { 2687 PetscCall(DMPlexMatSetClosureRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, In, c, elemMat, INSERT_VALUES)); 2688 } else { 2689 PetscCall(DMPlexMatSetClosureGeneral(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, In, c, elemMat, INSERT_VALUES)); 2690 } 2691 } 2692 for (f = 0; f < Nf; ++f) PetscCall(PetscFEDestroy(&feRef[f])); 2693 PetscCall(PetscFree2(feRef,fvRef)); 2694 PetscCall(PetscFree(elemMat)); 2695 PetscCall(MatAssemblyBegin(In, MAT_FINAL_ASSEMBLY)); 2696 PetscCall(MatAssemblyEnd(In, MAT_FINAL_ASSEMBLY)); 2697 if (mesh->printFEM > 1) { 2698 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)In), "%s:\n", name)); 2699 PetscCall(MatChop(In, 1.0e-10)); 2700 PetscCall(MatView(In, NULL)); 2701 } 2702 PetscCall(PetscLogEventEnd(DMPLEX_InterpolatorFEM,dmc,dmf,0,0)); 2703 PetscFunctionReturn(0); 2704 } 2705 2706 PetscErrorCode DMPlexComputeMassMatrixNested(DM dmc, DM dmf, Mat mass, void *user) 2707 { 2708 SETERRQ(PetscObjectComm((PetscObject) dmc), PETSC_ERR_SUP, "Laziness"); 2709 } 2710 2711 /*@ 2712 DMPlexComputeInterpolatorGeneral - Form the local portion of the interpolation matrix I from the coarse DM to a non-nested fine DM. 2713 2714 Input Parameters: 2715 + dmf - The fine mesh 2716 . dmc - The coarse mesh 2717 - user - The user context 2718 2719 Output Parameter: 2720 . In - The interpolation matrix 2721 2722 Level: developer 2723 2724 .seealso: DMPlexComputeInterpolatorNested(), DMPlexComputeJacobianFEM() 2725 @*/ 2726 PetscErrorCode DMPlexComputeInterpolatorGeneral(DM dmc, DM dmf, Mat In, void *user) 2727 { 2728 DM_Plex *mesh = (DM_Plex *) dmf->data; 2729 const char *name = "Interpolator"; 2730 PetscDS prob; 2731 PetscSection fsection, csection, globalFSection, globalCSection; 2732 PetscHSetIJ ht; 2733 PetscLayout rLayout; 2734 PetscInt *dnz, *onz; 2735 PetscInt locRows, rStart, rEnd; 2736 PetscReal *x, *v0, *J, *invJ, detJ; 2737 PetscReal *v0c, *Jc, *invJc, detJc; 2738 PetscScalar *elemMat; 2739 PetscInt dim, Nf, field, totDim, cStart, cEnd, cell, ccell; 2740 2741 PetscFunctionBegin; 2742 PetscCall(PetscLogEventBegin(DMPLEX_InterpolatorFEM,dmc,dmf,0,0)); 2743 PetscCall(DMGetCoordinateDim(dmc, &dim)); 2744 PetscCall(DMGetDS(dmc, &prob)); 2745 PetscCall(PetscDSGetWorkspace(prob, &x, NULL, NULL, NULL, NULL)); 2746 PetscCall(PetscDSGetNumFields(prob, &Nf)); 2747 PetscCall(PetscMalloc3(dim,&v0,dim*dim,&J,dim*dim,&invJ)); 2748 PetscCall(PetscMalloc3(dim,&v0c,dim*dim,&Jc,dim*dim,&invJc)); 2749 PetscCall(DMGetLocalSection(dmf, &fsection)); 2750 PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 2751 PetscCall(DMGetLocalSection(dmc, &csection)); 2752 PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 2753 PetscCall(DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd)); 2754 PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 2755 PetscCall(PetscMalloc1(totDim, &elemMat)); 2756 2757 PetscCall(MatGetLocalSize(In, &locRows, NULL)); 2758 PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject) In), &rLayout)); 2759 PetscCall(PetscLayoutSetLocalSize(rLayout, locRows)); 2760 PetscCall(PetscLayoutSetBlockSize(rLayout, 1)); 2761 PetscCall(PetscLayoutSetUp(rLayout)); 2762 PetscCall(PetscLayoutGetRange(rLayout, &rStart, &rEnd)); 2763 PetscCall(PetscLayoutDestroy(&rLayout)); 2764 PetscCall(PetscCalloc2(locRows,&dnz,locRows,&onz)); 2765 PetscCall(PetscHSetIJCreate(&ht)); 2766 for (field = 0; field < Nf; ++field) { 2767 PetscObject obj; 2768 PetscClassId id; 2769 PetscDualSpace Q = NULL; 2770 PetscQuadrature f; 2771 const PetscReal *qpoints; 2772 PetscInt Nc, Np, fpdim, i, d; 2773 2774 PetscCall(PetscDSGetDiscretization(prob, field, &obj)); 2775 PetscCall(PetscObjectGetClassId(obj, &id)); 2776 if (id == PETSCFE_CLASSID) { 2777 PetscFE fe = (PetscFE) obj; 2778 2779 PetscCall(PetscFEGetDualSpace(fe, &Q)); 2780 PetscCall(PetscFEGetNumComponents(fe, &Nc)); 2781 } else if (id == PETSCFV_CLASSID) { 2782 PetscFV fv = (PetscFV) obj; 2783 2784 PetscCall(PetscFVGetDualSpace(fv, &Q)); 2785 Nc = 1; 2786 } 2787 PetscCall(PetscDualSpaceGetDimension(Q, &fpdim)); 2788 /* For each fine grid cell */ 2789 for (cell = cStart; cell < cEnd; ++cell) { 2790 PetscInt *findices, *cindices; 2791 PetscInt numFIndices, numCIndices; 2792 2793 PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 2794 PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ)); 2795 PetscCheck(numFIndices == fpdim,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fine indices %D != %D dual basis vecs", numFIndices, fpdim); 2796 for (i = 0; i < fpdim; ++i) { 2797 Vec pointVec; 2798 PetscScalar *pV; 2799 PetscSF coarseCellSF = NULL; 2800 const PetscSFNode *coarseCells; 2801 PetscInt numCoarseCells, q, c; 2802 2803 /* Get points from the dual basis functional quadrature */ 2804 PetscCall(PetscDualSpaceGetFunctional(Q, i, &f)); 2805 PetscCall(PetscQuadratureGetData(f, NULL, NULL, &Np, &qpoints, NULL)); 2806 PetscCall(VecCreateSeq(PETSC_COMM_SELF, Np*dim, &pointVec)); 2807 PetscCall(VecSetBlockSize(pointVec, dim)); 2808 PetscCall(VecGetArray(pointVec, &pV)); 2809 for (q = 0; q < Np; ++q) { 2810 const PetscReal xi0[3] = {-1., -1., -1.}; 2811 2812 /* Transform point to real space */ 2813 CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q*dim], x); 2814 for (d = 0; d < dim; ++d) pV[q*dim+d] = x[d]; 2815 } 2816 PetscCall(VecRestoreArray(pointVec, &pV)); 2817 /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */ 2818 /* OPT: Pack all quad points from fine cell */ 2819 PetscCall(DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF)); 2820 PetscCall(PetscSFViewFromOptions(coarseCellSF, NULL, "-interp_sf_view")); 2821 /* Update preallocation info */ 2822 PetscCall(PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells)); 2823 PetscCheck(numCoarseCells == Np,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Not all closure points located"); 2824 { 2825 PetscHashIJKey key; 2826 PetscBool missing; 2827 2828 key.i = findices[i]; 2829 if (key.i >= 0) { 2830 /* Get indices for coarse elements */ 2831 for (ccell = 0; ccell < numCoarseCells; ++ccell) { 2832 PetscCall(DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 2833 for (c = 0; c < numCIndices; ++c) { 2834 key.j = cindices[c]; 2835 if (key.j < 0) continue; 2836 PetscCall(PetscHSetIJQueryAdd(ht, key, &missing)); 2837 if (missing) { 2838 if ((key.j >= rStart) && (key.j < rEnd)) ++dnz[key.i-rStart]; 2839 else ++onz[key.i-rStart]; 2840 } 2841 } 2842 PetscCall(DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 2843 } 2844 } 2845 } 2846 PetscCall(PetscSFDestroy(&coarseCellSF)); 2847 PetscCall(VecDestroy(&pointVec)); 2848 } 2849 PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 2850 } 2851 } 2852 PetscCall(PetscHSetIJDestroy(&ht)); 2853 PetscCall(MatXAIJSetPreallocation(In, 1, dnz, onz, NULL, NULL)); 2854 PetscCall(MatSetOption(In, MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE)); 2855 PetscCall(PetscFree2(dnz,onz)); 2856 for (field = 0; field < Nf; ++field) { 2857 PetscObject obj; 2858 PetscClassId id; 2859 PetscDualSpace Q = NULL; 2860 PetscTabulation T = NULL; 2861 PetscQuadrature f; 2862 const PetscReal *qpoints, *qweights; 2863 PetscInt Nc, qNc, Np, fpdim, i, d; 2864 2865 PetscCall(PetscDSGetDiscretization(prob, field, &obj)); 2866 PetscCall(PetscObjectGetClassId(obj, &id)); 2867 if (id == PETSCFE_CLASSID) { 2868 PetscFE fe = (PetscFE) obj; 2869 2870 PetscCall(PetscFEGetDualSpace(fe, &Q)); 2871 PetscCall(PetscFEGetNumComponents(fe, &Nc)); 2872 PetscCall(PetscFECreateTabulation(fe, 1, 1, x, 0, &T)); 2873 } else if (id == PETSCFV_CLASSID) { 2874 PetscFV fv = (PetscFV) obj; 2875 2876 PetscCall(PetscFVGetDualSpace(fv, &Q)); 2877 Nc = 1; 2878 } else SETERRQ(PetscObjectComm((PetscObject)dmc),PETSC_ERR_ARG_WRONG,"Unknown discretization type for field %D",field); 2879 PetscCall(PetscDualSpaceGetDimension(Q, &fpdim)); 2880 /* For each fine grid cell */ 2881 for (cell = cStart; cell < cEnd; ++cell) { 2882 PetscInt *findices, *cindices; 2883 PetscInt numFIndices, numCIndices; 2884 2885 PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 2886 PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ)); 2887 PetscCheck(numFIndices == fpdim,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fine indices %D != %D dual basis vecs", numFIndices, fpdim); 2888 for (i = 0; i < fpdim; ++i) { 2889 Vec pointVec; 2890 PetscScalar *pV; 2891 PetscSF coarseCellSF = NULL; 2892 const PetscSFNode *coarseCells; 2893 PetscInt numCoarseCells, cpdim, q, c, j; 2894 2895 /* Get points from the dual basis functional quadrature */ 2896 PetscCall(PetscDualSpaceGetFunctional(Q, i, &f)); 2897 PetscCall(PetscQuadratureGetData(f, NULL, &qNc, &Np, &qpoints, &qweights)); 2898 PetscCheck(qNc == Nc,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of components in quadrature %D does not match coarse field %D", qNc, Nc); 2899 PetscCall(VecCreateSeq(PETSC_COMM_SELF, Np*dim, &pointVec)); 2900 PetscCall(VecSetBlockSize(pointVec, dim)); 2901 PetscCall(VecGetArray(pointVec, &pV)); 2902 for (q = 0; q < Np; ++q) { 2903 const PetscReal xi0[3] = {-1., -1., -1.}; 2904 2905 /* Transform point to real space */ 2906 CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q*dim], x); 2907 for (d = 0; d < dim; ++d) pV[q*dim+d] = x[d]; 2908 } 2909 PetscCall(VecRestoreArray(pointVec, &pV)); 2910 /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */ 2911 /* OPT: Read this out from preallocation information */ 2912 PetscCall(DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF)); 2913 /* Update preallocation info */ 2914 PetscCall(PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells)); 2915 PetscCheck(numCoarseCells == Np,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Not all closure points located"); 2916 PetscCall(VecGetArray(pointVec, &pV)); 2917 for (ccell = 0; ccell < numCoarseCells; ++ccell) { 2918 PetscReal pVReal[3]; 2919 const PetscReal xi0[3] = {-1., -1., -1.}; 2920 2921 PetscCall(DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 2922 /* Transform points from real space to coarse reference space */ 2923 PetscCall(DMPlexComputeCellGeometryFEM(dmc, coarseCells[ccell].index, NULL, v0c, Jc, invJc, &detJc)); 2924 for (d = 0; d < dim; ++d) pVReal[d] = PetscRealPart(pV[ccell*dim+d]); 2925 CoordinatesRealToRef(dim, dim, xi0, v0c, invJc, pVReal, x); 2926 2927 if (id == PETSCFE_CLASSID) { 2928 PetscFE fe = (PetscFE) obj; 2929 2930 /* Evaluate coarse basis on contained point */ 2931 PetscCall(PetscFEGetDimension(fe, &cpdim)); 2932 PetscCall(PetscFEComputeTabulation(fe, 1, x, 0, T)); 2933 PetscCall(PetscArrayzero(elemMat, cpdim)); 2934 /* Get elemMat entries by multiplying by weight */ 2935 for (j = 0; j < cpdim; ++j) { 2936 for (c = 0; c < Nc; ++c) elemMat[j] += T->T[0][j*Nc + c]*qweights[ccell*qNc + c]; 2937 } 2938 } else { 2939 cpdim = 1; 2940 for (j = 0; j < cpdim; ++j) { 2941 for (c = 0; c < Nc; ++c) elemMat[j] += 1.0*qweights[ccell*qNc + c]; 2942 } 2943 } 2944 /* Update interpolator */ 2945 if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat)); 2946 PetscCheck(numCIndices == cpdim,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %D != %D", numCIndices, cpdim); 2947 PetscCall(MatSetValues(In, 1, &findices[i], numCIndices, cindices, elemMat, INSERT_VALUES)); 2948 PetscCall(DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 2949 } 2950 PetscCall(VecRestoreArray(pointVec, &pV)); 2951 PetscCall(PetscSFDestroy(&coarseCellSF)); 2952 PetscCall(VecDestroy(&pointVec)); 2953 } 2954 PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 2955 } 2956 if (id == PETSCFE_CLASSID) PetscCall(PetscTabulationDestroy(&T)); 2957 } 2958 PetscCall(PetscFree3(v0,J,invJ)); 2959 PetscCall(PetscFree3(v0c,Jc,invJc)); 2960 PetscCall(PetscFree(elemMat)); 2961 PetscCall(MatAssemblyBegin(In, MAT_FINAL_ASSEMBLY)); 2962 PetscCall(MatAssemblyEnd(In, MAT_FINAL_ASSEMBLY)); 2963 PetscCall(PetscLogEventEnd(DMPLEX_InterpolatorFEM,dmc,dmf,0,0)); 2964 PetscFunctionReturn(0); 2965 } 2966 2967 /*@ 2968 DMPlexComputeMassMatrixGeneral - Form the local portion of the mass matrix M from the coarse DM to a non-nested fine DM. 2969 2970 Input Parameters: 2971 + dmf - The fine mesh 2972 . dmc - The coarse mesh 2973 - user - The user context 2974 2975 Output Parameter: 2976 . mass - The mass matrix 2977 2978 Level: developer 2979 2980 .seealso: DMPlexComputeMassMatrixNested(), DMPlexComputeInterpolatorNested(), DMPlexComputeInterpolatorGeneral(), DMPlexComputeJacobianFEM() 2981 @*/ 2982 PetscErrorCode DMPlexComputeMassMatrixGeneral(DM dmc, DM dmf, Mat mass, void *user) 2983 { 2984 DM_Plex *mesh = (DM_Plex *) dmf->data; 2985 const char *name = "Mass Matrix"; 2986 PetscDS prob; 2987 PetscSection fsection, csection, globalFSection, globalCSection; 2988 PetscHSetIJ ht; 2989 PetscLayout rLayout; 2990 PetscInt *dnz, *onz; 2991 PetscInt locRows, rStart, rEnd; 2992 PetscReal *x, *v0, *J, *invJ, detJ; 2993 PetscReal *v0c, *Jc, *invJc, detJc; 2994 PetscScalar *elemMat; 2995 PetscInt dim, Nf, field, totDim, cStart, cEnd, cell, ccell; 2996 2997 PetscFunctionBegin; 2998 PetscCall(DMGetCoordinateDim(dmc, &dim)); 2999 PetscCall(DMGetDS(dmc, &prob)); 3000 PetscCall(PetscDSGetWorkspace(prob, &x, NULL, NULL, NULL, NULL)); 3001 PetscCall(PetscDSGetNumFields(prob, &Nf)); 3002 PetscCall(PetscMalloc3(dim,&v0,dim*dim,&J,dim*dim,&invJ)); 3003 PetscCall(PetscMalloc3(dim,&v0c,dim*dim,&Jc,dim*dim,&invJc)); 3004 PetscCall(DMGetLocalSection(dmf, &fsection)); 3005 PetscCall(DMGetGlobalSection(dmf, &globalFSection)); 3006 PetscCall(DMGetLocalSection(dmc, &csection)); 3007 PetscCall(DMGetGlobalSection(dmc, &globalCSection)); 3008 PetscCall(DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd)); 3009 PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 3010 PetscCall(PetscMalloc1(totDim, &elemMat)); 3011 3012 PetscCall(MatGetLocalSize(mass, &locRows, NULL)); 3013 PetscCall(PetscLayoutCreate(PetscObjectComm((PetscObject) mass), &rLayout)); 3014 PetscCall(PetscLayoutSetLocalSize(rLayout, locRows)); 3015 PetscCall(PetscLayoutSetBlockSize(rLayout, 1)); 3016 PetscCall(PetscLayoutSetUp(rLayout)); 3017 PetscCall(PetscLayoutGetRange(rLayout, &rStart, &rEnd)); 3018 PetscCall(PetscLayoutDestroy(&rLayout)); 3019 PetscCall(PetscCalloc2(locRows,&dnz,locRows,&onz)); 3020 PetscCall(PetscHSetIJCreate(&ht)); 3021 for (field = 0; field < Nf; ++field) { 3022 PetscObject obj; 3023 PetscClassId id; 3024 PetscQuadrature quad; 3025 const PetscReal *qpoints; 3026 PetscInt Nq, Nc, i, d; 3027 3028 PetscCall(PetscDSGetDiscretization(prob, field, &obj)); 3029 PetscCall(PetscObjectGetClassId(obj, &id)); 3030 if (id == PETSCFE_CLASSID) PetscCall(PetscFEGetQuadrature((PetscFE) obj, &quad)); 3031 else PetscCall(PetscFVGetQuadrature((PetscFV) obj, &quad)); 3032 PetscCall(PetscQuadratureGetData(quad, NULL, &Nc, &Nq, &qpoints, NULL)); 3033 /* For each fine grid cell */ 3034 for (cell = cStart; cell < cEnd; ++cell) { 3035 Vec pointVec; 3036 PetscScalar *pV; 3037 PetscSF coarseCellSF = NULL; 3038 const PetscSFNode *coarseCells; 3039 PetscInt numCoarseCells, q, c; 3040 PetscInt *findices, *cindices; 3041 PetscInt numFIndices, numCIndices; 3042 3043 PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 3044 PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ)); 3045 /* Get points from the quadrature */ 3046 PetscCall(VecCreateSeq(PETSC_COMM_SELF, Nq*dim, &pointVec)); 3047 PetscCall(VecSetBlockSize(pointVec, dim)); 3048 PetscCall(VecGetArray(pointVec, &pV)); 3049 for (q = 0; q < Nq; ++q) { 3050 const PetscReal xi0[3] = {-1., -1., -1.}; 3051 3052 /* Transform point to real space */ 3053 CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q*dim], x); 3054 for (d = 0; d < dim; ++d) pV[q*dim+d] = x[d]; 3055 } 3056 PetscCall(VecRestoreArray(pointVec, &pV)); 3057 /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */ 3058 PetscCall(DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF)); 3059 PetscCall(PetscSFViewFromOptions(coarseCellSF, NULL, "-interp_sf_view")); 3060 /* Update preallocation info */ 3061 PetscCall(PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells)); 3062 PetscCheck(numCoarseCells == Nq,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Not all closure points located"); 3063 { 3064 PetscHashIJKey key; 3065 PetscBool missing; 3066 3067 for (i = 0; i < numFIndices; ++i) { 3068 key.i = findices[i]; 3069 if (key.i >= 0) { 3070 /* Get indices for coarse elements */ 3071 for (ccell = 0; ccell < numCoarseCells; ++ccell) { 3072 PetscCall(DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 3073 for (c = 0; c < numCIndices; ++c) { 3074 key.j = cindices[c]; 3075 if (key.j < 0) continue; 3076 PetscCall(PetscHSetIJQueryAdd(ht, key, &missing)); 3077 if (missing) { 3078 if ((key.j >= rStart) && (key.j < rEnd)) ++dnz[key.i-rStart]; 3079 else ++onz[key.i-rStart]; 3080 } 3081 } 3082 PetscCall(DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 3083 } 3084 } 3085 } 3086 } 3087 PetscCall(PetscSFDestroy(&coarseCellSF)); 3088 PetscCall(VecDestroy(&pointVec)); 3089 PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 3090 } 3091 } 3092 PetscCall(PetscHSetIJDestroy(&ht)); 3093 PetscCall(MatXAIJSetPreallocation(mass, 1, dnz, onz, NULL, NULL)); 3094 PetscCall(MatSetOption(mass, MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE)); 3095 PetscCall(PetscFree2(dnz,onz)); 3096 for (field = 0; field < Nf; ++field) { 3097 PetscObject obj; 3098 PetscClassId id; 3099 PetscTabulation T, Tfine; 3100 PetscQuadrature quad; 3101 const PetscReal *qpoints, *qweights; 3102 PetscInt Nq, Nc, i, d; 3103 3104 PetscCall(PetscDSGetDiscretization(prob, field, &obj)); 3105 PetscCall(PetscObjectGetClassId(obj, &id)); 3106 if (id == PETSCFE_CLASSID) { 3107 PetscCall(PetscFEGetQuadrature((PetscFE) obj, &quad)); 3108 PetscCall(PetscFEGetCellTabulation((PetscFE) obj, 1, &Tfine)); 3109 PetscCall(PetscFECreateTabulation((PetscFE) obj, 1, 1, x, 0, &T)); 3110 } else { 3111 PetscCall(PetscFVGetQuadrature((PetscFV) obj, &quad)); 3112 } 3113 PetscCall(PetscQuadratureGetData(quad, NULL, &Nc, &Nq, &qpoints, &qweights)); 3114 /* For each fine grid cell */ 3115 for (cell = cStart; cell < cEnd; ++cell) { 3116 Vec pointVec; 3117 PetscScalar *pV; 3118 PetscSF coarseCellSF = NULL; 3119 const PetscSFNode *coarseCells; 3120 PetscInt numCoarseCells, cpdim, q, c, j; 3121 PetscInt *findices, *cindices; 3122 PetscInt numFIndices, numCIndices; 3123 3124 PetscCall(DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 3125 PetscCall(DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ)); 3126 /* Get points from the quadrature */ 3127 PetscCall(VecCreateSeq(PETSC_COMM_SELF, Nq*dim, &pointVec)); 3128 PetscCall(VecSetBlockSize(pointVec, dim)); 3129 PetscCall(VecGetArray(pointVec, &pV)); 3130 for (q = 0; q < Nq; ++q) { 3131 const PetscReal xi0[3] = {-1., -1., -1.}; 3132 3133 /* Transform point to real space */ 3134 CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q*dim], x); 3135 for (d = 0; d < dim; ++d) pV[q*dim+d] = x[d]; 3136 } 3137 PetscCall(VecRestoreArray(pointVec, &pV)); 3138 /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */ 3139 PetscCall(DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF)); 3140 /* Update matrix */ 3141 PetscCall(PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells)); 3142 PetscCheck(numCoarseCells == Nq,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Not all closure points located"); 3143 PetscCall(VecGetArray(pointVec, &pV)); 3144 for (ccell = 0; ccell < numCoarseCells; ++ccell) { 3145 PetscReal pVReal[3]; 3146 const PetscReal xi0[3] = {-1., -1., -1.}; 3147 3148 PetscCall(DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 3149 /* Transform points from real space to coarse reference space */ 3150 PetscCall(DMPlexComputeCellGeometryFEM(dmc, coarseCells[ccell].index, NULL, v0c, Jc, invJc, &detJc)); 3151 for (d = 0; d < dim; ++d) pVReal[d] = PetscRealPart(pV[ccell*dim+d]); 3152 CoordinatesRealToRef(dim, dim, xi0, v0c, invJc, pVReal, x); 3153 3154 if (id == PETSCFE_CLASSID) { 3155 PetscFE fe = (PetscFE) obj; 3156 3157 /* Evaluate coarse basis on contained point */ 3158 PetscCall(PetscFEGetDimension(fe, &cpdim)); 3159 PetscCall(PetscFEComputeTabulation(fe, 1, x, 0, T)); 3160 /* Get elemMat entries by multiplying by weight */ 3161 for (i = 0; i < numFIndices; ++i) { 3162 PetscCall(PetscArrayzero(elemMat, cpdim)); 3163 for (j = 0; j < cpdim; ++j) { 3164 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; 3165 } 3166 /* Update interpolator */ 3167 if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat)); 3168 PetscCheck(numCIndices == cpdim,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %D != %D", numCIndices, cpdim); 3169 PetscCall(MatSetValues(mass, 1, &findices[i], numCIndices, cindices, elemMat, ADD_VALUES)); 3170 } 3171 } else { 3172 cpdim = 1; 3173 for (i = 0; i < numFIndices; ++i) { 3174 PetscCall(PetscArrayzero(elemMat, cpdim)); 3175 for (j = 0; j < cpdim; ++j) { 3176 for (c = 0; c < Nc; ++c) elemMat[j] += 1.0*1.0*qweights[ccell*Nc + c]*detJ; 3177 } 3178 /* Update interpolator */ 3179 if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat)); 3180 PetscCall(PetscPrintf(PETSC_COMM_SELF, "Nq: %D %D Nf: %D %D Nc: %D %D\n", ccell, Nq, i, numFIndices, j, numCIndices)); 3181 PetscCheck(numCIndices == cpdim,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %D != %D", numCIndices, cpdim); 3182 PetscCall(MatSetValues(mass, 1, &findices[i], numCIndices, cindices, elemMat, ADD_VALUES)); 3183 } 3184 } 3185 PetscCall(DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL)); 3186 } 3187 PetscCall(VecRestoreArray(pointVec, &pV)); 3188 PetscCall(PetscSFDestroy(&coarseCellSF)); 3189 PetscCall(VecDestroy(&pointVec)); 3190 PetscCall(DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL)); 3191 } 3192 if (id == PETSCFE_CLASSID) PetscCall(PetscTabulationDestroy(&T)); 3193 } 3194 PetscCall(PetscFree3(v0,J,invJ)); 3195 PetscCall(PetscFree3(v0c,Jc,invJc)); 3196 PetscCall(PetscFree(elemMat)); 3197 PetscCall(MatAssemblyBegin(mass, MAT_FINAL_ASSEMBLY)); 3198 PetscCall(MatAssemblyEnd(mass, MAT_FINAL_ASSEMBLY)); 3199 PetscFunctionReturn(0); 3200 } 3201 3202 /*@ 3203 DMPlexComputeInjectorFEM - Compute a mapping from coarse unknowns to fine unknowns 3204 3205 Input Parameters: 3206 + dmc - The coarse mesh 3207 - dmf - The fine mesh 3208 - user - The user context 3209 3210 Output Parameter: 3211 . sc - The mapping 3212 3213 Level: developer 3214 3215 .seealso: DMPlexComputeInterpolatorNested(), DMPlexComputeJacobianFEM() 3216 @*/ 3217 PetscErrorCode DMPlexComputeInjectorFEM(DM dmc, DM dmf, VecScatter *sc, void *user) 3218 { 3219 PetscDS prob; 3220 PetscFE *feRef; 3221 PetscFV *fvRef; 3222 Vec fv, cv; 3223 IS fis, cis; 3224 PetscSection fsection, fglobalSection, csection, cglobalSection; 3225 PetscInt *cmap, *cellCIndices, *cellFIndices, *cindices, *findices; 3226 PetscInt cTotDim, fTotDim = 0, Nf, f, field, cStart, cEnd, c, dim, d, startC, endC, offsetC, offsetF, m; 3227 PetscBool *needAvg; 3228 3229 PetscFunctionBegin; 3230 PetscCall(PetscLogEventBegin(DMPLEX_InjectorFEM,dmc,dmf,0,0)); 3231 PetscCall(DMGetDimension(dmf, &dim)); 3232 PetscCall(DMGetLocalSection(dmf, &fsection)); 3233 PetscCall(DMGetGlobalSection(dmf, &fglobalSection)); 3234 PetscCall(DMGetLocalSection(dmc, &csection)); 3235 PetscCall(DMGetGlobalSection(dmc, &cglobalSection)); 3236 PetscCall(PetscSectionGetNumFields(fsection, &Nf)); 3237 PetscCall(DMPlexGetSimplexOrBoxCells(dmc, 0, &cStart, &cEnd)); 3238 PetscCall(DMGetDS(dmc, &prob)); 3239 PetscCall(PetscCalloc3(Nf,&feRef,Nf,&fvRef,Nf,&needAvg)); 3240 for (f = 0; f < Nf; ++f) { 3241 PetscObject obj; 3242 PetscClassId id; 3243 PetscInt fNb = 0, Nc = 0; 3244 3245 PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 3246 PetscCall(PetscObjectGetClassId(obj, &id)); 3247 if (id == PETSCFE_CLASSID) { 3248 PetscFE fe = (PetscFE) obj; 3249 PetscSpace sp; 3250 PetscInt maxDegree; 3251 3252 PetscCall(PetscFERefine(fe, &feRef[f])); 3253 PetscCall(PetscFEGetDimension(feRef[f], &fNb)); 3254 PetscCall(PetscFEGetNumComponents(fe, &Nc)); 3255 PetscCall(PetscFEGetBasisSpace(fe, &sp)); 3256 PetscCall(PetscSpaceGetDegree(sp, NULL, &maxDegree)); 3257 if (!maxDegree) needAvg[f] = PETSC_TRUE; 3258 } else if (id == PETSCFV_CLASSID) { 3259 PetscFV fv = (PetscFV) obj; 3260 PetscDualSpace Q; 3261 3262 PetscCall(PetscFVRefine(fv, &fvRef[f])); 3263 PetscCall(PetscFVGetDualSpace(fvRef[f], &Q)); 3264 PetscCall(PetscDualSpaceGetDimension(Q, &fNb)); 3265 PetscCall(PetscFVGetNumComponents(fv, &Nc)); 3266 needAvg[f] = PETSC_TRUE; 3267 } 3268 fTotDim += fNb; 3269 } 3270 PetscCall(PetscDSGetTotalDimension(prob, &cTotDim)); 3271 PetscCall(PetscMalloc1(cTotDim,&cmap)); 3272 for (field = 0, offsetC = 0, offsetF = 0; field < Nf; ++field) { 3273 PetscFE feC; 3274 PetscFV fvC; 3275 PetscDualSpace QF, QC; 3276 PetscInt order = -1, NcF, NcC, fpdim, cpdim; 3277 3278 if (feRef[field]) { 3279 PetscCall(PetscDSGetDiscretization(prob, field, (PetscObject *) &feC)); 3280 PetscCall(PetscFEGetNumComponents(feC, &NcC)); 3281 PetscCall(PetscFEGetNumComponents(feRef[field], &NcF)); 3282 PetscCall(PetscFEGetDualSpace(feRef[field], &QF)); 3283 PetscCall(PetscDualSpaceGetOrder(QF, &order)); 3284 PetscCall(PetscDualSpaceGetDimension(QF, &fpdim)); 3285 PetscCall(PetscFEGetDualSpace(feC, &QC)); 3286 PetscCall(PetscDualSpaceGetDimension(QC, &cpdim)); 3287 } else { 3288 PetscCall(PetscDSGetDiscretization(prob, field, (PetscObject *) &fvC)); 3289 PetscCall(PetscFVGetNumComponents(fvC, &NcC)); 3290 PetscCall(PetscFVGetNumComponents(fvRef[field], &NcF)); 3291 PetscCall(PetscFVGetDualSpace(fvRef[field], &QF)); 3292 PetscCall(PetscDualSpaceGetDimension(QF, &fpdim)); 3293 PetscCall(PetscFVGetDualSpace(fvC, &QC)); 3294 PetscCall(PetscDualSpaceGetDimension(QC, &cpdim)); 3295 } 3296 PetscCheck(NcF == NcC,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of components in fine space field %D does not match coarse field %D", NcF, NcC); 3297 for (c = 0; c < cpdim; ++c) { 3298 PetscQuadrature cfunc; 3299 const PetscReal *cqpoints, *cqweights; 3300 PetscInt NqcC, NpC; 3301 PetscBool found = PETSC_FALSE; 3302 3303 PetscCall(PetscDualSpaceGetFunctional(QC, c, &cfunc)); 3304 PetscCall(PetscQuadratureGetData(cfunc, NULL, &NqcC, &NpC, &cqpoints, &cqweights)); 3305 PetscCheck(NqcC == NcC,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of quadrature components %D must match number of field components %D", NqcC, NcC); 3306 PetscCheckFalse(NpC != 1 && feRef[field],PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Do not know how to do injection for moments"); 3307 for (f = 0; f < fpdim; ++f) { 3308 PetscQuadrature ffunc; 3309 const PetscReal *fqpoints, *fqweights; 3310 PetscReal sum = 0.0; 3311 PetscInt NqcF, NpF; 3312 3313 PetscCall(PetscDualSpaceGetFunctional(QF, f, &ffunc)); 3314 PetscCall(PetscQuadratureGetData(ffunc, NULL, &NqcF, &NpF, &fqpoints, &fqweights)); 3315 PetscCheck(NqcF == NcF,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of quadrature components %D must match number of field components %D", NqcF, NcF); 3316 if (NpC != NpF) continue; 3317 for (d = 0; d < dim; ++d) sum += PetscAbsReal(cqpoints[d] - fqpoints[d]); 3318 if (sum > 1.0e-9) continue; 3319 for (d = 0; d < NcC; ++d) sum += PetscAbsReal(cqweights[d]*fqweights[d]); 3320 if (sum < 1.0e-9) continue; 3321 cmap[offsetC+c] = offsetF+f; 3322 found = PETSC_TRUE; 3323 break; 3324 } 3325 if (!found) { 3326 /* TODO We really want the average here, but some asshole put VecScatter in the interface */ 3327 if (fvRef[field] || (feRef[field] && order == 0)) { 3328 cmap[offsetC+c] = offsetF+0; 3329 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate matching functional for injection"); 3330 } 3331 } 3332 offsetC += cpdim; 3333 offsetF += fpdim; 3334 } 3335 for (f = 0; f < Nf; ++f) {PetscCall(PetscFEDestroy(&feRef[f]));PetscCall(PetscFVDestroy(&fvRef[f]));} 3336 PetscCall(PetscFree3(feRef,fvRef,needAvg)); 3337 3338 PetscCall(DMGetGlobalVector(dmf, &fv)); 3339 PetscCall(DMGetGlobalVector(dmc, &cv)); 3340 PetscCall(VecGetOwnershipRange(cv, &startC, &endC)); 3341 PetscCall(PetscSectionGetConstrainedStorageSize(cglobalSection, &m)); 3342 PetscCall(PetscMalloc2(cTotDim,&cellCIndices,fTotDim,&cellFIndices)); 3343 PetscCall(PetscMalloc1(m,&cindices)); 3344 PetscCall(PetscMalloc1(m,&findices)); 3345 for (d = 0; d < m; ++d) cindices[d] = findices[d] = -1; 3346 for (c = cStart; c < cEnd; ++c) { 3347 PetscCall(DMPlexMatGetClosureIndicesRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, c, cellCIndices, cellFIndices)); 3348 for (d = 0; d < cTotDim; ++d) { 3349 if ((cellCIndices[d] < startC) || (cellCIndices[d] >= endC)) continue; 3350 PetscCheck(!(findices[cellCIndices[d]-startC] >= 0) || !(findices[cellCIndices[d]-startC] != cellFIndices[cmap[d]]),PETSC_COMM_SELF, PETSC_ERR_PLIB, "Coarse dof %D maps to both %D and %D", cindices[cellCIndices[d]-startC], findices[cellCIndices[d]-startC], cellFIndices[cmap[d]]); 3351 cindices[cellCIndices[d]-startC] = cellCIndices[d]; 3352 findices[cellCIndices[d]-startC] = cellFIndices[cmap[d]]; 3353 } 3354 } 3355 PetscCall(PetscFree(cmap)); 3356 PetscCall(PetscFree2(cellCIndices,cellFIndices)); 3357 3358 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, m, cindices, PETSC_OWN_POINTER, &cis)); 3359 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, m, findices, PETSC_OWN_POINTER, &fis)); 3360 PetscCall(VecScatterCreate(cv, cis, fv, fis, sc)); 3361 PetscCall(ISDestroy(&cis)); 3362 PetscCall(ISDestroy(&fis)); 3363 PetscCall(DMRestoreGlobalVector(dmf, &fv)); 3364 PetscCall(DMRestoreGlobalVector(dmc, &cv)); 3365 PetscCall(PetscLogEventEnd(DMPLEX_InjectorFEM,dmc,dmf,0,0)); 3366 PetscFunctionReturn(0); 3367 } 3368 3369 /*@C 3370 DMPlexGetCellFields - Retrieve the field values values for a chunk of cells 3371 3372 Input Parameters: 3373 + dm - The DM 3374 . cellIS - The cells to include 3375 . locX - A local vector with the solution fields 3376 . locX_t - A local vector with solution field time derivatives, or NULL 3377 - locA - A local vector with auxiliary fields, or NULL 3378 3379 Output Parameters: 3380 + u - The field coefficients 3381 . u_t - The fields derivative coefficients 3382 - a - The auxiliary field coefficients 3383 3384 Level: developer 3385 3386 .seealso: DMPlexGetFaceFields() 3387 @*/ 3388 PetscErrorCode DMPlexGetCellFields(DM dm, IS cellIS, Vec locX, Vec locX_t, Vec locA, PetscScalar **u, PetscScalar **u_t, PetscScalar **a) 3389 { 3390 DM plex, plexA = NULL; 3391 DMEnclosureType encAux; 3392 PetscSection section, sectionAux; 3393 PetscDS prob; 3394 const PetscInt *cells; 3395 PetscInt cStart, cEnd, numCells, totDim, totDimAux, c; 3396 3397 PetscFunctionBegin; 3398 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3399 PetscValidHeaderSpecific(locX, VEC_CLASSID, 3); 3400 if (locX_t) {PetscValidHeaderSpecific(locX_t, VEC_CLASSID, 4);} 3401 if (locA) {PetscValidHeaderSpecific(locA, VEC_CLASSID, 5);} 3402 PetscValidPointer(u, 6); 3403 PetscValidPointer(u_t, 7); 3404 PetscValidPointer(a, 8); 3405 PetscCall(DMPlexConvertPlex(dm, &plex, PETSC_FALSE)); 3406 PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 3407 PetscCall(DMGetLocalSection(dm, §ion)); 3408 PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob)); 3409 PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 3410 if (locA) { 3411 DM dmAux; 3412 PetscDS probAux; 3413 3414 PetscCall(VecGetDM(locA, &dmAux)); 3415 PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 3416 PetscCall(DMPlexConvertPlex(dmAux, &plexA, PETSC_FALSE)); 3417 PetscCall(DMGetLocalSection(dmAux, §ionAux)); 3418 PetscCall(DMGetDS(dmAux, &probAux)); 3419 PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 3420 } 3421 numCells = cEnd - cStart; 3422 PetscCall(DMGetWorkArray(dm, numCells*totDim, MPIU_SCALAR, u)); 3423 if (locX_t) PetscCall(DMGetWorkArray(dm, numCells*totDim, MPIU_SCALAR, u_t)); else {*u_t = NULL;} 3424 if (locA) PetscCall(DMGetWorkArray(dm, numCells*totDimAux, MPIU_SCALAR, a)); else {*a = NULL;} 3425 for (c = cStart; c < cEnd; ++c) { 3426 const PetscInt cell = cells ? cells[c] : c; 3427 const PetscInt cind = c - cStart; 3428 PetscScalar *x = NULL, *x_t = NULL, *ul = *u, *ul_t = *u_t, *al = *a; 3429 PetscInt i; 3430 3431 PetscCall(DMPlexVecGetClosure(plex, section, locX, cell, NULL, &x)); 3432 for (i = 0; i < totDim; ++i) ul[cind*totDim+i] = x[i]; 3433 PetscCall(DMPlexVecRestoreClosure(plex, section, locX, cell, NULL, &x)); 3434 if (locX_t) { 3435 PetscCall(DMPlexVecGetClosure(plex, section, locX_t, cell, NULL, &x_t)); 3436 for (i = 0; i < totDim; ++i) ul_t[cind*totDim+i] = x_t[i]; 3437 PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, cell, NULL, &x_t)); 3438 } 3439 if (locA) { 3440 PetscInt subcell; 3441 PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, cell, &subcell)); 3442 PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subcell, NULL, &x)); 3443 for (i = 0; i < totDimAux; ++i) al[cind*totDimAux+i] = x[i]; 3444 PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subcell, NULL, &x)); 3445 } 3446 } 3447 PetscCall(DMDestroy(&plex)); 3448 if (locA) PetscCall(DMDestroy(&plexA)); 3449 PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 3450 PetscFunctionReturn(0); 3451 } 3452 3453 /*@C 3454 DMPlexRestoreCellFields - Restore the field values values for a chunk of cells 3455 3456 Input Parameters: 3457 + dm - The DM 3458 . cellIS - The cells to include 3459 . locX - A local vector with the solution fields 3460 . locX_t - A local vector with solution field time derivatives, or NULL 3461 - locA - A local vector with auxiliary fields, or NULL 3462 3463 Output Parameters: 3464 + u - The field coefficients 3465 . u_t - The fields derivative coefficients 3466 - a - The auxiliary field coefficients 3467 3468 Level: developer 3469 3470 .seealso: DMPlexGetFaceFields() 3471 @*/ 3472 PetscErrorCode DMPlexRestoreCellFields(DM dm, IS cellIS, Vec locX, Vec locX_t, Vec locA, PetscScalar **u, PetscScalar **u_t, PetscScalar **a) 3473 { 3474 PetscFunctionBegin; 3475 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, u)); 3476 if (locX_t) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, u_t)); 3477 if (locA) PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, a)); 3478 PetscFunctionReturn(0); 3479 } 3480 3481 /* 3482 Get the auxiliary field vectors for the negative side (s = 0) and positive side (s = 1) of the interfaace 3483 */ 3484 static PetscErrorCode DMPlexGetHybridAuxFields(DM dm, DM dmAux[], PetscDS dsAux[], IS cellIS, Vec locA[], PetscScalar *a[]) 3485 { 3486 DM plexA[2]; 3487 DMEnclosureType encAux[2]; 3488 PetscSection sectionAux[2]; 3489 const PetscInt *cells; 3490 PetscInt cStart, cEnd, numCells, c, s, totDimAux[2]; 3491 3492 PetscFunctionBegin; 3493 PetscValidPointer(locA, 5); 3494 if (!locA[0] || !locA[1]) PetscFunctionReturn(0); 3495 PetscValidPointer(dmAux, 2); 3496 PetscValidPointer(dsAux, 3); 3497 PetscValidPointer(a, 6); 3498 PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 3499 numCells = cEnd - cStart; 3500 for (s = 0; s < 2; ++s) { 3501 PetscValidHeaderSpecific(dmAux[s], DM_CLASSID, 2); 3502 PetscValidHeaderSpecific(dsAux[s], PETSCDS_CLASSID, 3); 3503 PetscValidHeaderSpecific(locA[s], VEC_CLASSID, 5); 3504 PetscCall(DMPlexConvertPlex(dmAux[s], &plexA[s], PETSC_FALSE)); 3505 PetscCall(DMGetEnclosureRelation(dmAux[s], dm, &encAux[s])); 3506 PetscCall(DMGetLocalSection(dmAux[s], §ionAux[s])); 3507 PetscCall(PetscDSGetTotalDimension(dsAux[s], &totDimAux[s])); 3508 PetscCall(DMGetWorkArray(dmAux[s], numCells*totDimAux[s], MPIU_SCALAR, &a[s])); 3509 } 3510 for (c = cStart; c < cEnd; ++c) { 3511 const PetscInt cell = cells ? cells[c] : c; 3512 const PetscInt cind = c - cStart; 3513 const PetscInt *cone, *ornt; 3514 3515 PetscCall(DMPlexGetCone(dm, cell, &cone)); 3516 PetscCall(DMPlexGetConeOrientation(dm, cell, &ornt)); 3517 PetscCheckFalse(ornt[0],PETSC_COMM_SELF, PETSC_ERR_SUP, "Face %D in hybrid cell %D has orientation %D != 0", cone[0], cell, ornt[0]); 3518 for (s = 0; s < 2; ++s) { 3519 const PetscInt *support; 3520 PetscScalar *x = NULL, *al = a[s]; 3521 const PetscInt tdA = totDimAux[s]; 3522 PetscInt ssize, scell; 3523 PetscInt subface, Na, i; 3524 3525 PetscCall(DMPlexGetSupport(dm, cone[s], &support)); 3526 PetscCall(DMPlexGetSupportSize(dm, cone[s], &ssize)); 3527 PetscCheck(ssize == 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %D from cell %D has support size %D != 2", cone[s], cell, ssize); 3528 if (support[0] == cell) scell = support[1]; 3529 else if (support[1] == cell) scell = support[0]; 3530 else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %D does not have cell %D in its support", cone[s], cell); 3531 3532 PetscCall(DMGetEnclosurePoint(plexA[s], dm, encAux[s], scell, &subface)); 3533 PetscCall(DMPlexVecGetClosure(plexA[s], sectionAux[s], locA[s], subface, &Na, &x)); 3534 for (i = 0; i < Na; ++i) al[cind*tdA+i] = x[i]; 3535 PetscCall(DMPlexVecRestoreClosure(plexA[s], sectionAux[s], locA[s], subface, &Na, &x)); 3536 } 3537 } 3538 for (s = 0; s < 2; ++s) PetscCall(DMDestroy(&plexA[s])); 3539 PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 3540 PetscFunctionReturn(0); 3541 } 3542 3543 static PetscErrorCode DMPlexRestoreHybridAuxFields(DM dmAux[], PetscDS dsAux[], IS cellIS, Vec locA[], PetscScalar *a[]) 3544 { 3545 PetscFunctionBegin; 3546 if (!locA[0] || !locA[1]) PetscFunctionReturn(0); 3547 PetscCall(DMRestoreWorkArray(dmAux[0], 0, MPIU_SCALAR, &a[0])); 3548 PetscCall(DMRestoreWorkArray(dmAux[1], 0, MPIU_SCALAR, &a[1])); 3549 PetscFunctionReturn(0); 3550 } 3551 3552 /*@C 3553 DMPlexGetFaceFields - Retrieve the field values values for a chunk of faces 3554 3555 Input Parameters: 3556 + dm - The DM 3557 . fStart - The first face to include 3558 . fEnd - The first face to exclude 3559 . locX - A local vector with the solution fields 3560 . locX_t - A local vector with solution field time derivatives, or NULL 3561 . faceGeometry - A local vector with face geometry 3562 . cellGeometry - A local vector with cell geometry 3563 - locaGrad - A local vector with field gradients, or NULL 3564 3565 Output Parameters: 3566 + Nface - The number of faces with field values 3567 . uL - The field values at the left side of the face 3568 - uR - The field values at the right side of the face 3569 3570 Level: developer 3571 3572 .seealso: DMPlexGetCellFields() 3573 @*/ 3574 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) 3575 { 3576 DM dmFace, dmCell, dmGrad = NULL; 3577 PetscSection section; 3578 PetscDS prob; 3579 DMLabel ghostLabel; 3580 const PetscScalar *facegeom, *cellgeom, *x, *lgrad; 3581 PetscBool *isFE; 3582 PetscInt dim, Nf, f, Nc, numFaces = fEnd - fStart, iface, face; 3583 3584 PetscFunctionBegin; 3585 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3586 PetscValidHeaderSpecific(locX, VEC_CLASSID, 4); 3587 if (locX_t) {PetscValidHeaderSpecific(locX_t, VEC_CLASSID, 5);} 3588 PetscValidHeaderSpecific(faceGeometry, VEC_CLASSID, 6); 3589 PetscValidHeaderSpecific(cellGeometry, VEC_CLASSID, 7); 3590 if (locGrad) {PetscValidHeaderSpecific(locGrad, VEC_CLASSID, 8);} 3591 PetscValidPointer(uL, 10); 3592 PetscValidPointer(uR, 11); 3593 PetscCall(DMGetDimension(dm, &dim)); 3594 PetscCall(DMGetDS(dm, &prob)); 3595 PetscCall(DMGetLocalSection(dm, §ion)); 3596 PetscCall(PetscDSGetNumFields(prob, &Nf)); 3597 PetscCall(PetscDSGetTotalComponents(prob, &Nc)); 3598 PetscCall(PetscMalloc1(Nf, &isFE)); 3599 for (f = 0; f < Nf; ++f) { 3600 PetscObject obj; 3601 PetscClassId id; 3602 3603 PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 3604 PetscCall(PetscObjectGetClassId(obj, &id)); 3605 if (id == PETSCFE_CLASSID) {isFE[f] = PETSC_TRUE;} 3606 else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;} 3607 else {isFE[f] = PETSC_FALSE;} 3608 } 3609 PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 3610 PetscCall(VecGetArrayRead(locX, &x)); 3611 PetscCall(VecGetDM(faceGeometry, &dmFace)); 3612 PetscCall(VecGetArrayRead(faceGeometry, &facegeom)); 3613 PetscCall(VecGetDM(cellGeometry, &dmCell)); 3614 PetscCall(VecGetArrayRead(cellGeometry, &cellgeom)); 3615 if (locGrad) { 3616 PetscCall(VecGetDM(locGrad, &dmGrad)); 3617 PetscCall(VecGetArrayRead(locGrad, &lgrad)); 3618 } 3619 PetscCall(DMGetWorkArray(dm, numFaces*Nc, MPIU_SCALAR, uL)); 3620 PetscCall(DMGetWorkArray(dm, numFaces*Nc, MPIU_SCALAR, uR)); 3621 /* Right now just eat the extra work for FE (could make a cell loop) */ 3622 for (face = fStart, iface = 0; face < fEnd; ++face) { 3623 const PetscInt *cells; 3624 PetscFVFaceGeom *fg; 3625 PetscFVCellGeom *cgL, *cgR; 3626 PetscScalar *xL, *xR, *gL, *gR; 3627 PetscScalar *uLl = *uL, *uRl = *uR; 3628 PetscInt ghost, nsupp, nchild; 3629 3630 PetscCall(DMLabelGetValue(ghostLabel, face, &ghost)); 3631 PetscCall(DMPlexGetSupportSize(dm, face, &nsupp)); 3632 PetscCall(DMPlexGetTreeChildren(dm, face, &nchild, NULL)); 3633 if (ghost >= 0 || nsupp > 2 || nchild > 0) continue; 3634 PetscCall(DMPlexPointLocalRead(dmFace, face, facegeom, &fg)); 3635 PetscCall(DMPlexGetSupport(dm, face, &cells)); 3636 PetscCall(DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cgL)); 3637 PetscCall(DMPlexPointLocalRead(dmCell, cells[1], cellgeom, &cgR)); 3638 for (f = 0; f < Nf; ++f) { 3639 PetscInt off; 3640 3641 PetscCall(PetscDSGetComponentOffset(prob, f, &off)); 3642 if (isFE[f]) { 3643 const PetscInt *cone; 3644 PetscInt comp, coneSizeL, coneSizeR, faceLocL, faceLocR, ldof, rdof, d; 3645 3646 xL = xR = NULL; 3647 PetscCall(PetscSectionGetFieldComponents(section, f, &comp)); 3648 PetscCall(DMPlexVecGetClosure(dm, section, locX, cells[0], &ldof, (PetscScalar **) &xL)); 3649 PetscCall(DMPlexVecGetClosure(dm, section, locX, cells[1], &rdof, (PetscScalar **) &xR)); 3650 PetscCall(DMPlexGetCone(dm, cells[0], &cone)); 3651 PetscCall(DMPlexGetConeSize(dm, cells[0], &coneSizeL)); 3652 for (faceLocL = 0; faceLocL < coneSizeL; ++faceLocL) if (cone[faceLocL] == face) break; 3653 PetscCall(DMPlexGetCone(dm, cells[1], &cone)); 3654 PetscCall(DMPlexGetConeSize(dm, cells[1], &coneSizeR)); 3655 for (faceLocR = 0; faceLocR < coneSizeR; ++faceLocR) if (cone[faceLocR] == face) break; 3656 PetscCheckFalse(faceLocL == coneSizeL && faceLocR == coneSizeR,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %D in cone of cell %D or cell %D", face, cells[0], cells[1]); 3657 /* Check that FEM field has values in the right cell (sometimes its an FV ghost cell) */ 3658 /* TODO: this is a hack that might not be right for nonconforming */ 3659 if (faceLocL < coneSizeL) { 3660 PetscCall(PetscFEEvaluateFaceFields_Internal(prob, f, faceLocL, xL, &uLl[iface*Nc+off])); 3661 if (rdof == ldof && faceLocR < coneSizeR) PetscCall(PetscFEEvaluateFaceFields_Internal(prob, f, faceLocR, xR, &uRl[iface*Nc+off])); 3662 else {for (d = 0; d < comp; ++d) uRl[iface*Nc+off+d] = uLl[iface*Nc+off+d];} 3663 } 3664 else { 3665 PetscCall(PetscFEEvaluateFaceFields_Internal(prob, f, faceLocR, xR, &uRl[iface*Nc+off])); 3666 PetscCall(PetscSectionGetFieldComponents(section, f, &comp)); 3667 for (d = 0; d < comp; ++d) uLl[iface*Nc+off+d] = uRl[iface*Nc+off+d]; 3668 } 3669 PetscCall(DMPlexVecRestoreClosure(dm, section, locX, cells[0], &ldof, (PetscScalar **) &xL)); 3670 PetscCall(DMPlexVecRestoreClosure(dm, section, locX, cells[1], &rdof, (PetscScalar **) &xR)); 3671 } else { 3672 PetscFV fv; 3673 PetscInt numComp, c; 3674 3675 PetscCall(PetscDSGetDiscretization(prob, f, (PetscObject *) &fv)); 3676 PetscCall(PetscFVGetNumComponents(fv, &numComp)); 3677 PetscCall(DMPlexPointLocalFieldRead(dm, cells[0], f, x, &xL)); 3678 PetscCall(DMPlexPointLocalFieldRead(dm, cells[1], f, x, &xR)); 3679 if (dmGrad) { 3680 PetscReal dxL[3], dxR[3]; 3681 3682 PetscCall(DMPlexPointLocalRead(dmGrad, cells[0], lgrad, &gL)); 3683 PetscCall(DMPlexPointLocalRead(dmGrad, cells[1], lgrad, &gR)); 3684 DMPlex_WaxpyD_Internal(dim, -1, cgL->centroid, fg->centroid, dxL); 3685 DMPlex_WaxpyD_Internal(dim, -1, cgR->centroid, fg->centroid, dxR); 3686 for (c = 0; c < numComp; ++c) { 3687 uLl[iface*Nc+off+c] = xL[c] + DMPlex_DotD_Internal(dim, &gL[c*dim], dxL); 3688 uRl[iface*Nc+off+c] = xR[c] + DMPlex_DotD_Internal(dim, &gR[c*dim], dxR); 3689 } 3690 } else { 3691 for (c = 0; c < numComp; ++c) { 3692 uLl[iface*Nc+off+c] = xL[c]; 3693 uRl[iface*Nc+off+c] = xR[c]; 3694 } 3695 } 3696 } 3697 } 3698 ++iface; 3699 } 3700 *Nface = iface; 3701 PetscCall(VecRestoreArrayRead(locX, &x)); 3702 PetscCall(VecRestoreArrayRead(faceGeometry, &facegeom)); 3703 PetscCall(VecRestoreArrayRead(cellGeometry, &cellgeom)); 3704 if (locGrad) { 3705 PetscCall(VecRestoreArrayRead(locGrad, &lgrad)); 3706 } 3707 PetscCall(PetscFree(isFE)); 3708 PetscFunctionReturn(0); 3709 } 3710 3711 /*@C 3712 DMPlexRestoreFaceFields - Restore the field values values for a chunk of faces 3713 3714 Input Parameters: 3715 + dm - The DM 3716 . fStart - The first face to include 3717 . fEnd - The first face to exclude 3718 . locX - A local vector with the solution fields 3719 . locX_t - A local vector with solution field time derivatives, or NULL 3720 . faceGeometry - A local vector with face geometry 3721 . cellGeometry - A local vector with cell geometry 3722 - locaGrad - A local vector with field gradients, or NULL 3723 3724 Output Parameters: 3725 + Nface - The number of faces with field values 3726 . uL - The field values at the left side of the face 3727 - uR - The field values at the right side of the face 3728 3729 Level: developer 3730 3731 .seealso: DMPlexGetFaceFields() 3732 @*/ 3733 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) 3734 { 3735 PetscFunctionBegin; 3736 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, uL)); 3737 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_SCALAR, uR)); 3738 PetscFunctionReturn(0); 3739 } 3740 3741 /*@C 3742 DMPlexGetFaceGeometry - Retrieve the geometric values for a chunk of faces 3743 3744 Input Parameters: 3745 + dm - The DM 3746 . fStart - The first face to include 3747 . fEnd - The first face to exclude 3748 . faceGeometry - A local vector with face geometry 3749 - cellGeometry - A local vector with cell geometry 3750 3751 Output Parameters: 3752 + Nface - The number of faces with field values 3753 . fgeom - The extract the face centroid and normal 3754 - vol - The cell volume 3755 3756 Level: developer 3757 3758 .seealso: DMPlexGetCellFields() 3759 @*/ 3760 PetscErrorCode DMPlexGetFaceGeometry(DM dm, PetscInt fStart, PetscInt fEnd, Vec faceGeometry, Vec cellGeometry, PetscInt *Nface, PetscFVFaceGeom **fgeom, PetscReal **vol) 3761 { 3762 DM dmFace, dmCell; 3763 DMLabel ghostLabel; 3764 const PetscScalar *facegeom, *cellgeom; 3765 PetscInt dim, numFaces = fEnd - fStart, iface, face; 3766 3767 PetscFunctionBegin; 3768 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3769 PetscValidHeaderSpecific(faceGeometry, VEC_CLASSID, 4); 3770 PetscValidHeaderSpecific(cellGeometry, VEC_CLASSID, 5); 3771 PetscValidPointer(fgeom, 7); 3772 PetscValidPointer(vol, 8); 3773 PetscCall(DMGetDimension(dm, &dim)); 3774 PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 3775 PetscCall(VecGetDM(faceGeometry, &dmFace)); 3776 PetscCall(VecGetArrayRead(faceGeometry, &facegeom)); 3777 PetscCall(VecGetDM(cellGeometry, &dmCell)); 3778 PetscCall(VecGetArrayRead(cellGeometry, &cellgeom)); 3779 PetscCall(PetscMalloc1(numFaces, fgeom)); 3780 PetscCall(DMGetWorkArray(dm, numFaces*2, MPIU_SCALAR, vol)); 3781 for (face = fStart, iface = 0; face < fEnd; ++face) { 3782 const PetscInt *cells; 3783 PetscFVFaceGeom *fg; 3784 PetscFVCellGeom *cgL, *cgR; 3785 PetscFVFaceGeom *fgeoml = *fgeom; 3786 PetscReal *voll = *vol; 3787 PetscInt ghost, d, nchild, nsupp; 3788 3789 PetscCall(DMLabelGetValue(ghostLabel, face, &ghost)); 3790 PetscCall(DMPlexGetSupportSize(dm, face, &nsupp)); 3791 PetscCall(DMPlexGetTreeChildren(dm, face, &nchild, NULL)); 3792 if (ghost >= 0 || nsupp > 2 || nchild > 0) continue; 3793 PetscCall(DMPlexPointLocalRead(dmFace, face, facegeom, &fg)); 3794 PetscCall(DMPlexGetSupport(dm, face, &cells)); 3795 PetscCall(DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cgL)); 3796 PetscCall(DMPlexPointLocalRead(dmCell, cells[1], cellgeom, &cgR)); 3797 for (d = 0; d < dim; ++d) { 3798 fgeoml[iface].centroid[d] = fg->centroid[d]; 3799 fgeoml[iface].normal[d] = fg->normal[d]; 3800 } 3801 voll[iface*2+0] = cgL->volume; 3802 voll[iface*2+1] = cgR->volume; 3803 ++iface; 3804 } 3805 *Nface = iface; 3806 PetscCall(VecRestoreArrayRead(faceGeometry, &facegeom)); 3807 PetscCall(VecRestoreArrayRead(cellGeometry, &cellgeom)); 3808 PetscFunctionReturn(0); 3809 } 3810 3811 /*@C 3812 DMPlexRestoreFaceGeometry - Restore the field values values for a chunk of faces 3813 3814 Input Parameters: 3815 + dm - The DM 3816 . fStart - The first face to include 3817 . fEnd - The first face to exclude 3818 . faceGeometry - A local vector with face geometry 3819 - cellGeometry - A local vector with cell geometry 3820 3821 Output Parameters: 3822 + Nface - The number of faces with field values 3823 . fgeom - The extract the face centroid and normal 3824 - vol - The cell volume 3825 3826 Level: developer 3827 3828 .seealso: DMPlexGetFaceFields() 3829 @*/ 3830 PetscErrorCode DMPlexRestoreFaceGeometry(DM dm, PetscInt fStart, PetscInt fEnd, Vec faceGeometry, Vec cellGeometry, PetscInt *Nface, PetscFVFaceGeom **fgeom, PetscReal **vol) 3831 { 3832 PetscFunctionBegin; 3833 PetscCall(PetscFree(*fgeom)); 3834 PetscCall(DMRestoreWorkArray(dm, 0, MPIU_REAL, vol)); 3835 PetscFunctionReturn(0); 3836 } 3837 3838 PetscErrorCode DMSNESGetFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom) 3839 { 3840 char composeStr[33] = {0}; 3841 PetscObjectId id; 3842 PetscContainer container; 3843 3844 PetscFunctionBegin; 3845 PetscCall(PetscObjectGetId((PetscObject)quad,&id)); 3846 PetscCall(PetscSNPrintf(composeStr, 32, "DMSNESGetFEGeom_%x\n", id)); 3847 PetscCall(PetscObjectQuery((PetscObject) pointIS, composeStr, (PetscObject *) &container)); 3848 if (container) { 3849 PetscCall(PetscContainerGetPointer(container, (void **) geom)); 3850 } else { 3851 PetscCall(DMFieldCreateFEGeom(coordField, pointIS, quad, faceData, geom)); 3852 PetscCall(PetscContainerCreate(PETSC_COMM_SELF,&container)); 3853 PetscCall(PetscContainerSetPointer(container, (void *) *geom)); 3854 PetscCall(PetscContainerSetUserDestroy(container, PetscContainerUserDestroy_PetscFEGeom)); 3855 PetscCall(PetscObjectCompose((PetscObject) pointIS, composeStr, (PetscObject) container)); 3856 PetscCall(PetscContainerDestroy(&container)); 3857 } 3858 PetscFunctionReturn(0); 3859 } 3860 3861 PetscErrorCode DMSNESRestoreFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom) 3862 { 3863 PetscFunctionBegin; 3864 *geom = NULL; 3865 PetscFunctionReturn(0); 3866 } 3867 3868 PetscErrorCode DMPlexComputeResidual_Patch_Internal(DM dm, PetscSection section, IS cellIS, PetscReal t, Vec locX, Vec locX_t, Vec locF, void *user) 3869 { 3870 DM_Plex *mesh = (DM_Plex *) dm->data; 3871 const char *name = "Residual"; 3872 DM dmAux = NULL; 3873 DMLabel ghostLabel = NULL; 3874 PetscDS prob = NULL; 3875 PetscDS probAux = NULL; 3876 PetscBool useFEM = PETSC_FALSE; 3877 PetscBool isImplicit = (locX_t || t == PETSC_MIN_REAL) ? PETSC_TRUE : PETSC_FALSE; 3878 DMField coordField = NULL; 3879 Vec locA; 3880 PetscScalar *u = NULL, *u_t, *a, *uL = NULL, *uR = NULL; 3881 IS chunkIS; 3882 const PetscInt *cells; 3883 PetscInt cStart, cEnd, numCells; 3884 PetscInt Nf, f, totDim, totDimAux, numChunks, cellChunkSize, chunk, fStart, fEnd; 3885 PetscInt maxDegree = PETSC_MAX_INT; 3886 PetscFormKey key; 3887 PetscQuadrature affineQuad = NULL, *quads = NULL; 3888 PetscFEGeom *affineGeom = NULL, **geoms = NULL; 3889 3890 PetscFunctionBegin; 3891 PetscCall(PetscLogEventBegin(DMPLEX_ResidualFEM,dm,0,0,0)); 3892 /* FEM+FVM */ 3893 /* 1: Get sizes from dm and dmAux */ 3894 PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 3895 PetscCall(DMGetDS(dm, &prob)); 3896 PetscCall(PetscDSGetNumFields(prob, &Nf)); 3897 PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 3898 PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &locA)); 3899 if (locA) { 3900 PetscCall(VecGetDM(locA, &dmAux)); 3901 PetscCall(DMGetDS(dmAux, &probAux)); 3902 PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 3903 } 3904 /* 2: Get geometric data */ 3905 for (f = 0; f < Nf; ++f) { 3906 PetscObject obj; 3907 PetscClassId id; 3908 PetscBool fimp; 3909 3910 PetscCall(PetscDSGetImplicit(prob, f, &fimp)); 3911 if (isImplicit != fimp) continue; 3912 PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 3913 PetscCall(PetscObjectGetClassId(obj, &id)); 3914 if (id == PETSCFE_CLASSID) {useFEM = PETSC_TRUE;} 3915 PetscCheck(id != PETSCFV_CLASSID,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Use of FVM with PCPATCH not yet implemented"); 3916 } 3917 if (useFEM) { 3918 PetscCall(DMGetCoordinateField(dm, &coordField)); 3919 PetscCall(DMFieldGetDegree(coordField,cellIS,NULL,&maxDegree)); 3920 if (maxDegree <= 1) { 3921 PetscCall(DMFieldCreateDefaultQuadrature(coordField,cellIS,&affineQuad)); 3922 if (affineQuad) { 3923 PetscCall(DMSNESGetFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom)); 3924 } 3925 } else { 3926 PetscCall(PetscCalloc2(Nf,&quads,Nf,&geoms)); 3927 for (f = 0; f < Nf; ++f) { 3928 PetscObject obj; 3929 PetscClassId id; 3930 PetscBool fimp; 3931 3932 PetscCall(PetscDSGetImplicit(prob, f, &fimp)); 3933 if (isImplicit != fimp) continue; 3934 PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 3935 PetscCall(PetscObjectGetClassId(obj, &id)); 3936 if (id == PETSCFE_CLASSID) { 3937 PetscFE fe = (PetscFE) obj; 3938 3939 PetscCall(PetscFEGetQuadrature(fe, &quads[f])); 3940 PetscCall(PetscObjectReference((PetscObject)quads[f])); 3941 PetscCall(DMSNESGetFEGeom(coordField,cellIS,quads[f],PETSC_FALSE,&geoms[f])); 3942 } 3943 } 3944 } 3945 } 3946 /* Loop over chunks */ 3947 PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 3948 PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 3949 if (useFEM) PetscCall(ISCreate(PETSC_COMM_SELF, &chunkIS)); 3950 numCells = cEnd - cStart; 3951 numChunks = 1; 3952 cellChunkSize = numCells/numChunks; 3953 numChunks = PetscMin(1,numCells); 3954 key.label = NULL; 3955 key.value = 0; 3956 key.part = 0; 3957 for (chunk = 0; chunk < numChunks; ++chunk) { 3958 PetscScalar *elemVec, *fluxL = NULL, *fluxR = NULL; 3959 PetscReal *vol = NULL; 3960 PetscFVFaceGeom *fgeom = NULL; 3961 PetscInt cS = cStart+chunk*cellChunkSize, cE = PetscMin(cS+cellChunkSize, cEnd), numCells = cE - cS, c; 3962 PetscInt numFaces = 0; 3963 3964 /* Extract field coefficients */ 3965 if (useFEM) { 3966 PetscCall(ISGetPointSubrange(chunkIS, cS, cE, cells)); 3967 PetscCall(DMPlexGetCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a)); 3968 PetscCall(DMGetWorkArray(dm, numCells*totDim, MPIU_SCALAR, &elemVec)); 3969 PetscCall(PetscArrayzero(elemVec, numCells*totDim)); 3970 } 3971 /* TODO We will interlace both our field coefficients (u, u_t, uL, uR, etc.) and our output (elemVec, fL, fR). I think this works */ 3972 /* Loop over fields */ 3973 for (f = 0; f < Nf; ++f) { 3974 PetscObject obj; 3975 PetscClassId id; 3976 PetscBool fimp; 3977 PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset; 3978 3979 key.field = f; 3980 PetscCall(PetscDSGetImplicit(prob, f, &fimp)); 3981 if (isImplicit != fimp) continue; 3982 PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 3983 PetscCall(PetscObjectGetClassId(obj, &id)); 3984 if (id == PETSCFE_CLASSID) { 3985 PetscFE fe = (PetscFE) obj; 3986 PetscFEGeom *geom = affineGeom ? affineGeom : geoms[f]; 3987 PetscFEGeom *chunkGeom = NULL; 3988 PetscQuadrature quad = affineQuad ? affineQuad : quads[f]; 3989 PetscInt Nq, Nb; 3990 3991 PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 3992 PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL)); 3993 PetscCall(PetscFEGetDimension(fe, &Nb)); 3994 blockSize = Nb; 3995 batchSize = numBlocks * blockSize; 3996 PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 3997 numChunks = numCells / (numBatches*batchSize); 3998 Ne = numChunks*numBatches*batchSize; 3999 Nr = numCells % (numBatches*batchSize); 4000 offset = numCells - Nr; 4001 /* Integrate FE residual to get elemVec (need fields at quadrature points) */ 4002 /* 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) */ 4003 PetscCall(PetscFEGeomGetChunk(geom,0,offset,&chunkGeom)); 4004 PetscCall(PetscFEIntegrateResidual(prob, key, Ne, chunkGeom, u, u_t, probAux, a, t, elemVec)); 4005 PetscCall(PetscFEGeomGetChunk(geom,offset,numCells,&chunkGeom)); 4006 PetscCall(PetscFEIntegrateResidual(prob, key, Nr, chunkGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, probAux, &a[offset*totDimAux], t, &elemVec[offset*totDim])); 4007 PetscCall(PetscFEGeomRestoreChunk(geom,offset,numCells,&chunkGeom)); 4008 } else if (id == PETSCFV_CLASSID) { 4009 PetscFV fv = (PetscFV) obj; 4010 4011 Ne = numFaces; 4012 /* Riemann solve over faces (need fields at face centroids) */ 4013 /* We need to evaluate FE fields at those coordinates */ 4014 PetscCall(PetscFVIntegrateRHSFunction(fv, prob, f, Ne, fgeom, vol, uL, uR, fluxL, fluxR)); 4015 } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", f); 4016 } 4017 /* Loop over domain */ 4018 if (useFEM) { 4019 /* Add elemVec to locX */ 4020 for (c = cS; c < cE; ++c) { 4021 const PetscInt cell = cells ? cells[c] : c; 4022 const PetscInt cind = c - cStart; 4023 4024 if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, name, totDim, &elemVec[cind*totDim])); 4025 if (ghostLabel) { 4026 PetscInt ghostVal; 4027 4028 PetscCall(DMLabelGetValue(ghostLabel,cell,&ghostVal)); 4029 if (ghostVal > 0) continue; 4030 } 4031 PetscCall(DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind*totDim], ADD_ALL_VALUES)); 4032 } 4033 } 4034 /* Handle time derivative */ 4035 if (locX_t) { 4036 PetscScalar *x_t, *fa; 4037 4038 PetscCall(VecGetArray(locF, &fa)); 4039 PetscCall(VecGetArray(locX_t, &x_t)); 4040 for (f = 0; f < Nf; ++f) { 4041 PetscFV fv; 4042 PetscObject obj; 4043 PetscClassId id; 4044 PetscInt pdim, d; 4045 4046 PetscCall(PetscDSGetDiscretization(prob, f, &obj)); 4047 PetscCall(PetscObjectGetClassId(obj, &id)); 4048 if (id != PETSCFV_CLASSID) continue; 4049 fv = (PetscFV) obj; 4050 PetscCall(PetscFVGetNumComponents(fv, &pdim)); 4051 for (c = cS; c < cE; ++c) { 4052 const PetscInt cell = cells ? cells[c] : c; 4053 PetscScalar *u_t, *r; 4054 4055 if (ghostLabel) { 4056 PetscInt ghostVal; 4057 4058 PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal)); 4059 if (ghostVal > 0) continue; 4060 } 4061 PetscCall(DMPlexPointLocalFieldRead(dm, cell, f, x_t, &u_t)); 4062 PetscCall(DMPlexPointLocalFieldRef(dm, cell, f, fa, &r)); 4063 for (d = 0; d < pdim; ++d) r[d] += u_t[d]; 4064 } 4065 } 4066 PetscCall(VecRestoreArray(locX_t, &x_t)); 4067 PetscCall(VecRestoreArray(locF, &fa)); 4068 } 4069 if (useFEM) { 4070 PetscCall(DMPlexRestoreCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a)); 4071 PetscCall(DMRestoreWorkArray(dm, numCells*totDim, MPIU_SCALAR, &elemVec)); 4072 } 4073 } 4074 if (useFEM) PetscCall(ISDestroy(&chunkIS)); 4075 PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 4076 /* TODO Could include boundary residual here (see DMPlexComputeResidual_Internal) */ 4077 if (useFEM) { 4078 if (maxDegree <= 1) { 4079 PetscCall(DMSNESRestoreFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom)); 4080 PetscCall(PetscQuadratureDestroy(&affineQuad)); 4081 } else { 4082 for (f = 0; f < Nf; ++f) { 4083 PetscCall(DMSNESRestoreFEGeom(coordField,cellIS,quads[f],PETSC_FALSE,&geoms[f])); 4084 PetscCall(PetscQuadratureDestroy(&quads[f])); 4085 } 4086 PetscCall(PetscFree2(quads,geoms)); 4087 } 4088 } 4089 PetscCall(PetscLogEventEnd(DMPLEX_ResidualFEM,dm,0,0,0)); 4090 PetscFunctionReturn(0); 4091 } 4092 4093 /* 4094 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 4095 4096 X - The local solution vector 4097 X_t - The local solution time derivative vector, or NULL 4098 */ 4099 PetscErrorCode DMPlexComputeJacobian_Patch_Internal(DM dm, PetscSection section, PetscSection globalSection, IS cellIS, 4100 PetscReal t, PetscReal X_tShift, Vec X, Vec X_t, Mat Jac, Mat JacP, void *ctx) 4101 { 4102 DM_Plex *mesh = (DM_Plex *) dm->data; 4103 const char *name = "Jacobian", *nameP = "JacobianPre"; 4104 DM dmAux = NULL; 4105 PetscDS prob, probAux = NULL; 4106 PetscSection sectionAux = NULL; 4107 Vec A; 4108 DMField coordField; 4109 PetscFEGeom *cgeomFEM; 4110 PetscQuadrature qGeom = NULL; 4111 Mat J = Jac, JP = JacP; 4112 PetscScalar *work, *u = NULL, *u_t = NULL, *a = NULL, *elemMat = NULL, *elemMatP = NULL, *elemMatD = NULL; 4113 PetscBool hasJac, hasPrec, hasDyn, assembleJac, *isFE, hasFV = PETSC_FALSE; 4114 const PetscInt *cells; 4115 PetscFormKey key; 4116 PetscInt Nf, fieldI, fieldJ, maxDegree, numCells, cStart, cEnd, numChunks, chunkSize, chunk, totDim, totDimAux = 0, sz, wsz, off = 0, offCell = 0; 4117 4118 PetscFunctionBegin; 4119 PetscCall(ISGetLocalSize(cellIS, &numCells)); 4120 PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 4121 PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM,dm,0,0,0)); 4122 PetscCall(DMGetDS(dm, &prob)); 4123 PetscCall(DMGetAuxiliaryVec(dm, NULL, 0, 0, &A)); 4124 if (A) { 4125 PetscCall(VecGetDM(A, &dmAux)); 4126 PetscCall(DMGetLocalSection(dmAux, §ionAux)); 4127 PetscCall(DMGetDS(dmAux, &probAux)); 4128 } 4129 /* Get flags */ 4130 PetscCall(PetscDSGetNumFields(prob, &Nf)); 4131 PetscCall(DMGetWorkArray(dm, Nf, MPIU_BOOL, &isFE)); 4132 for (fieldI = 0; fieldI < Nf; ++fieldI) { 4133 PetscObject disc; 4134 PetscClassId id; 4135 PetscCall(PetscDSGetDiscretization(prob, fieldI, &disc)); 4136 PetscCall(PetscObjectGetClassId(disc, &id)); 4137 if (id == PETSCFE_CLASSID) {isFE[fieldI] = PETSC_TRUE;} 4138 else if (id == PETSCFV_CLASSID) {hasFV = PETSC_TRUE; isFE[fieldI] = PETSC_FALSE;} 4139 } 4140 PetscCall(PetscDSHasJacobian(prob, &hasJac)); 4141 PetscCall(PetscDSHasJacobianPreconditioner(prob, &hasPrec)); 4142 PetscCall(PetscDSHasDynamicJacobian(prob, &hasDyn)); 4143 assembleJac = hasJac && hasPrec && (Jac != JacP) ? PETSC_TRUE : PETSC_FALSE; 4144 hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE; 4145 if (hasFV) PetscCall(MatSetOption(JP, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE)); /* No allocated space for FV stuff, so ignore the zero entries */ 4146 PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 4147 if (probAux) PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 4148 /* Compute batch sizes */ 4149 if (isFE[0]) { 4150 PetscFE fe; 4151 PetscQuadrature q; 4152 PetscInt numQuadPoints, numBatches, batchSize, numBlocks, blockSize, Nb; 4153 4154 PetscCall(PetscDSGetDiscretization(prob, 0, (PetscObject *) &fe)); 4155 PetscCall(PetscFEGetQuadrature(fe, &q)); 4156 PetscCall(PetscQuadratureGetData(q, NULL, NULL, &numQuadPoints, NULL, NULL)); 4157 PetscCall(PetscFEGetDimension(fe, &Nb)); 4158 PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 4159 blockSize = Nb*numQuadPoints; 4160 batchSize = numBlocks * blockSize; 4161 chunkSize = numBatches * batchSize; 4162 numChunks = numCells / chunkSize + numCells % chunkSize; 4163 PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 4164 } else { 4165 chunkSize = numCells; 4166 numChunks = 1; 4167 } 4168 /* Get work space */ 4169 wsz = (((X?1:0) + (X_t?1:0) + (dmAux?1:0))*totDim + ((hasJac?1:0) + (hasPrec?1:0) + (hasDyn?1:0))*totDim*totDim)*chunkSize; 4170 PetscCall(DMGetWorkArray(dm, wsz, MPIU_SCALAR, &work)); 4171 PetscCall(PetscArrayzero(work, wsz)); 4172 off = 0; 4173 u = X ? (sz = chunkSize*totDim, off += sz, work+off-sz) : NULL; 4174 u_t = X_t ? (sz = chunkSize*totDim, off += sz, work+off-sz) : NULL; 4175 a = dmAux ? (sz = chunkSize*totDimAux, off += sz, work+off-sz) : NULL; 4176 elemMat = hasJac ? (sz = chunkSize*totDim*totDim, off += sz, work+off-sz) : NULL; 4177 elemMatP = hasPrec ? (sz = chunkSize*totDim*totDim, off += sz, work+off-sz) : NULL; 4178 elemMatD = hasDyn ? (sz = chunkSize*totDim*totDim, off += sz, work+off-sz) : NULL; 4179 PetscCheck(off == wsz,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Error is workspace size %D should be %D", off, wsz); 4180 /* Setup geometry */ 4181 PetscCall(DMGetCoordinateField(dm, &coordField)); 4182 PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 4183 if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField, cellIS, &qGeom)); 4184 if (!qGeom) { 4185 PetscFE fe; 4186 4187 PetscCall(PetscDSGetDiscretization(prob, 0, (PetscObject *) &fe)); 4188 PetscCall(PetscFEGetQuadrature(fe, &qGeom)); 4189 PetscCall(PetscObjectReference((PetscObject) qGeom)); 4190 } 4191 PetscCall(DMSNESGetFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 4192 /* Compute volume integrals */ 4193 if (assembleJac) PetscCall(MatZeroEntries(J)); 4194 PetscCall(MatZeroEntries(JP)); 4195 key.label = NULL; 4196 key.value = 0; 4197 key.part = 0; 4198 for (chunk = 0; chunk < numChunks; ++chunk, offCell += chunkSize) { 4199 const PetscInt Ncell = PetscMin(chunkSize, numCells - offCell); 4200 PetscInt c; 4201 4202 /* Extract values */ 4203 for (c = 0; c < Ncell; ++c) { 4204 const PetscInt cell = cells ? cells[c+offCell] : c+offCell; 4205 PetscScalar *x = NULL, *x_t = NULL; 4206 PetscInt i; 4207 4208 if (X) { 4209 PetscCall(DMPlexVecGetClosure(dm, section, X, cell, NULL, &x)); 4210 for (i = 0; i < totDim; ++i) u[c*totDim+i] = x[i]; 4211 PetscCall(DMPlexVecRestoreClosure(dm, section, X, cell, NULL, &x)); 4212 } 4213 if (X_t) { 4214 PetscCall(DMPlexVecGetClosure(dm, section, X_t, cell, NULL, &x_t)); 4215 for (i = 0; i < totDim; ++i) u_t[c*totDim+i] = x_t[i]; 4216 PetscCall(DMPlexVecRestoreClosure(dm, section, X_t, cell, NULL, &x_t)); 4217 } 4218 if (dmAux) { 4219 PetscCall(DMPlexVecGetClosure(dmAux, sectionAux, A, cell, NULL, &x)); 4220 for (i = 0; i < totDimAux; ++i) a[c*totDimAux+i] = x[i]; 4221 PetscCall(DMPlexVecRestoreClosure(dmAux, sectionAux, A, cell, NULL, &x)); 4222 } 4223 } 4224 for (fieldI = 0; fieldI < Nf; ++fieldI) { 4225 PetscFE fe; 4226 PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fe)); 4227 for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 4228 key.field = fieldI*Nf + fieldJ; 4229 if (hasJac) PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMat)); 4230 if (hasPrec) PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, key, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMatP)); 4231 if (hasDyn) PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMatD)); 4232 } 4233 /* For finite volume, add the identity */ 4234 if (!isFE[fieldI]) { 4235 PetscFV fv; 4236 PetscInt eOffset = 0, Nc, fc, foff; 4237 4238 PetscCall(PetscDSGetFieldOffset(prob, fieldI, &foff)); 4239 PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fv)); 4240 PetscCall(PetscFVGetNumComponents(fv, &Nc)); 4241 for (c = 0; c < chunkSize; ++c, eOffset += totDim*totDim) { 4242 for (fc = 0; fc < Nc; ++fc) { 4243 const PetscInt i = foff + fc; 4244 if (hasJac) {elemMat [eOffset+i*totDim+i] = 1.0;} 4245 if (hasPrec) {elemMatP[eOffset+i*totDim+i] = 1.0;} 4246 } 4247 } 4248 } 4249 } 4250 /* Add contribution from X_t */ 4251 if (hasDyn) {for (c = 0; c < chunkSize*totDim*totDim; ++c) elemMat[c] += X_tShift*elemMatD[c];} 4252 /* Insert values into matrix */ 4253 for (c = 0; c < Ncell; ++c) { 4254 const PetscInt cell = cells ? cells[c+offCell] : c+offCell; 4255 if (mesh->printFEM > 1) { 4256 if (hasJac) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[(c-cStart)*totDim*totDim])); 4257 if (hasPrec) PetscCall(DMPrintCellMatrix(cell, nameP, totDim, totDim, &elemMatP[(c-cStart)*totDim*totDim])); 4258 } 4259 if (assembleJac) PetscCall(DMPlexMatSetClosure(dm, section, globalSection, Jac, cell, &elemMat[(c-cStart)*totDim*totDim], ADD_VALUES)); 4260 PetscCall(DMPlexMatSetClosure(dm, section, globalSection, JP, cell, &elemMat[(c-cStart)*totDim*totDim], ADD_VALUES)); 4261 } 4262 } 4263 /* Cleanup */ 4264 PetscCall(DMSNESRestoreFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM)); 4265 PetscCall(PetscQuadratureDestroy(&qGeom)); 4266 if (hasFV) PetscCall(MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_FALSE)); 4267 PetscCall(DMRestoreWorkArray(dm, Nf, MPIU_BOOL, &isFE)); 4268 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)); 4269 /* Compute boundary integrals */ 4270 /* PetscCall(DMPlexComputeBdJacobian_Internal(dm, X, X_t, t, X_tShift, Jac, JacP, ctx)); */ 4271 /* Assemble matrix */ 4272 if (assembleJac) {PetscCall(MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY));PetscCall(MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY));} 4273 PetscCall(MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY));PetscCall(MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY)); 4274 PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM,dm,0,0,0)); 4275 PetscFunctionReturn(0); 4276 } 4277 4278 /******** FEM Assembly Function ********/ 4279 4280 static PetscErrorCode DMConvertPlex_Internal(DM dm, DM *plex, PetscBool copy) 4281 { 4282 PetscBool isPlex; 4283 4284 PetscFunctionBegin; 4285 PetscCall(PetscObjectTypeCompare((PetscObject) dm, DMPLEX, &isPlex)); 4286 if (isPlex) { 4287 *plex = dm; 4288 PetscCall(PetscObjectReference((PetscObject) dm)); 4289 } else { 4290 PetscCall(PetscObjectQuery((PetscObject) dm, "dm_plex", (PetscObject *) plex)); 4291 if (!*plex) { 4292 PetscCall(DMConvert(dm,DMPLEX,plex)); 4293 PetscCall(PetscObjectCompose((PetscObject) dm, "dm_plex", (PetscObject) *plex)); 4294 if (copy) { 4295 PetscCall(DMCopyAuxiliaryVec(dm, *plex)); 4296 } 4297 } else { 4298 PetscCall(PetscObjectReference((PetscObject) *plex)); 4299 } 4300 } 4301 PetscFunctionReturn(0); 4302 } 4303 4304 /*@ 4305 DMPlexGetGeometryFVM - Return precomputed geometric data 4306 4307 Collective on DM 4308 4309 Input Parameter: 4310 . dm - The DM 4311 4312 Output Parameters: 4313 + facegeom - The values precomputed from face geometry 4314 . cellgeom - The values precomputed from cell geometry 4315 - minRadius - The minimum radius over the mesh of an inscribed sphere in a cell 4316 4317 Level: developer 4318 4319 .seealso: DMTSSetRHSFunctionLocal() 4320 @*/ 4321 PetscErrorCode DMPlexGetGeometryFVM(DM dm, Vec *facegeom, Vec *cellgeom, PetscReal *minRadius) 4322 { 4323 DM plex; 4324 4325 PetscFunctionBegin; 4326 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 4327 PetscCall(DMConvertPlex_Internal(dm,&plex,PETSC_TRUE)); 4328 PetscCall(DMPlexGetDataFVM(plex, NULL, cellgeom, facegeom, NULL)); 4329 if (minRadius) PetscCall(DMPlexGetMinRadius(plex, minRadius)); 4330 PetscCall(DMDestroy(&plex)); 4331 PetscFunctionReturn(0); 4332 } 4333 4334 /*@ 4335 DMPlexGetGradientDM - Return gradient data layout 4336 4337 Collective on DM 4338 4339 Input Parameters: 4340 + dm - The DM 4341 - fv - The PetscFV 4342 4343 Output Parameter: 4344 . dmGrad - The layout for gradient values 4345 4346 Level: developer 4347 4348 .seealso: DMPlexGetGeometryFVM() 4349 @*/ 4350 PetscErrorCode DMPlexGetGradientDM(DM dm, PetscFV fv, DM *dmGrad) 4351 { 4352 DM plex; 4353 PetscBool computeGradients; 4354 4355 PetscFunctionBegin; 4356 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 4357 PetscValidHeaderSpecific(fv,PETSCFV_CLASSID,2); 4358 PetscValidPointer(dmGrad,3); 4359 PetscCall(PetscFVGetComputeGradients(fv, &computeGradients)); 4360 if (!computeGradients) {*dmGrad = NULL; PetscFunctionReturn(0);} 4361 PetscCall(DMConvertPlex_Internal(dm,&plex,PETSC_TRUE)); 4362 PetscCall(DMPlexGetDataFVM(plex, fv, NULL, NULL, dmGrad)); 4363 PetscCall(DMDestroy(&plex)); 4364 PetscFunctionReturn(0); 4365 } 4366 4367 static PetscErrorCode DMPlexComputeBdResidual_Single_Internal(DM dm, PetscReal t, PetscWeakForm wf, PetscFormKey key, Vec locX, Vec locX_t, Vec locF, DMField coordField, IS facetIS) 4368 { 4369 DM_Plex *mesh = (DM_Plex *) dm->data; 4370 DM plex = NULL, plexA = NULL; 4371 DMEnclosureType encAux; 4372 PetscDS prob, probAux = NULL; 4373 PetscSection section, sectionAux = NULL; 4374 Vec locA = NULL; 4375 PetscScalar *u = NULL, *u_t = NULL, *a = NULL, *elemVec = NULL; 4376 PetscInt totDim, totDimAux = 0; 4377 4378 PetscFunctionBegin; 4379 PetscCall(DMConvert(dm, DMPLEX, &plex)); 4380 PetscCall(DMGetLocalSection(dm, §ion)); 4381 PetscCall(DMGetDS(dm, &prob)); 4382 PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 4383 PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &locA)); 4384 if (locA) { 4385 DM dmAux; 4386 4387 PetscCall(VecGetDM(locA, &dmAux)); 4388 PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 4389 PetscCall(DMConvert(dmAux, DMPLEX, &plexA)); 4390 PetscCall(DMGetDS(plexA, &probAux)); 4391 PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 4392 PetscCall(DMGetLocalSection(plexA, §ionAux)); 4393 } 4394 { 4395 PetscFEGeom *fgeom; 4396 PetscInt maxDegree; 4397 PetscQuadrature qGeom = NULL; 4398 IS pointIS; 4399 const PetscInt *points; 4400 PetscInt numFaces, face, Nq; 4401 4402 PetscCall(DMLabelGetStratumIS(key.label, key.value, &pointIS)); 4403 if (!pointIS) goto end; /* No points with that id on this process */ 4404 { 4405 IS isectIS; 4406 4407 /* TODO: Special cases of ISIntersect where it is quick to check a priori if one is a superset of the other */ 4408 PetscCall(ISIntersect_Caching_Internal(facetIS,pointIS,&isectIS)); 4409 PetscCall(ISDestroy(&pointIS)); 4410 pointIS = isectIS; 4411 } 4412 PetscCall(ISGetLocalSize(pointIS,&numFaces)); 4413 PetscCall(ISGetIndices(pointIS,&points)); 4414 PetscCall(PetscMalloc4(numFaces*totDim, &u, locX_t ? numFaces*totDim : 0, &u_t, numFaces*totDim, &elemVec, locA ? numFaces*totDimAux : 0, &a)); 4415 PetscCall(DMFieldGetDegree(coordField,pointIS,NULL,&maxDegree)); 4416 if (maxDegree <= 1) { 4417 PetscCall(DMFieldCreateDefaultQuadrature(coordField,pointIS,&qGeom)); 4418 } 4419 if (!qGeom) { 4420 PetscFE fe; 4421 4422 PetscCall(PetscDSGetDiscretization(prob, key.field, (PetscObject *) &fe)); 4423 PetscCall(PetscFEGetFaceQuadrature(fe, &qGeom)); 4424 PetscCall(PetscObjectReference((PetscObject)qGeom)); 4425 } 4426 PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL)); 4427 PetscCall(DMSNESGetFEGeom(coordField,pointIS,qGeom,PETSC_TRUE,&fgeom)); 4428 for (face = 0; face < numFaces; ++face) { 4429 const PetscInt point = points[face], *support; 4430 PetscScalar *x = NULL; 4431 PetscInt i; 4432 4433 PetscCall(DMPlexGetSupport(dm, point, &support)); 4434 PetscCall(DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x)); 4435 for (i = 0; i < totDim; ++i) u[face*totDim+i] = x[i]; 4436 PetscCall(DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x)); 4437 if (locX_t) { 4438 PetscCall(DMPlexVecGetClosure(plex, section, locX_t, support[0], NULL, &x)); 4439 for (i = 0; i < totDim; ++i) u_t[face*totDim+i] = x[i]; 4440 PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, support[0], NULL, &x)); 4441 } 4442 if (locA) { 4443 PetscInt subp; 4444 4445 PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp)); 4446 PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x)); 4447 for (i = 0; i < totDimAux; ++i) a[face*totDimAux+i] = x[i]; 4448 PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x)); 4449 } 4450 } 4451 PetscCall(PetscArrayzero(elemVec, numFaces*totDim)); 4452 { 4453 PetscFE fe; 4454 PetscInt Nb; 4455 PetscFEGeom *chunkGeom = NULL; 4456 /* Conforming batches */ 4457 PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize; 4458 /* Remainder */ 4459 PetscInt Nr, offset; 4460 4461 PetscCall(PetscDSGetDiscretization(prob, key.field, (PetscObject *) &fe)); 4462 PetscCall(PetscFEGetDimension(fe, &Nb)); 4463 PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 4464 /* TODO: documentation is unclear about what is going on with these numbers: how should Nb / Nq factor in ? */ 4465 blockSize = Nb; 4466 batchSize = numBlocks * blockSize; 4467 PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 4468 numChunks = numFaces / (numBatches*batchSize); 4469 Ne = numChunks*numBatches*batchSize; 4470 Nr = numFaces % (numBatches*batchSize); 4471 offset = numFaces - Nr; 4472 PetscCall(PetscFEGeomGetChunk(fgeom,0,offset,&chunkGeom)); 4473 PetscCall(PetscFEIntegrateBdResidual(prob, wf, key, Ne, chunkGeom, u, u_t, probAux, a, t, elemVec)); 4474 PetscCall(PetscFEGeomRestoreChunk(fgeom, 0, offset, &chunkGeom)); 4475 PetscCall(PetscFEGeomGetChunk(fgeom,offset,numFaces,&chunkGeom)); 4476 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])); 4477 PetscCall(PetscFEGeomRestoreChunk(fgeom,offset,numFaces,&chunkGeom)); 4478 } 4479 for (face = 0; face < numFaces; ++face) { 4480 const PetscInt point = points[face], *support; 4481 4482 if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(point, "BdResidual", totDim, &elemVec[face*totDim])); 4483 PetscCall(DMPlexGetSupport(plex, point, &support)); 4484 PetscCall(DMPlexVecSetClosure(plex, NULL, locF, support[0], &elemVec[face*totDim], ADD_ALL_VALUES)); 4485 } 4486 PetscCall(DMSNESRestoreFEGeom(coordField,pointIS,qGeom,PETSC_TRUE,&fgeom)); 4487 PetscCall(PetscQuadratureDestroy(&qGeom)); 4488 PetscCall(ISRestoreIndices(pointIS, &points)); 4489 PetscCall(ISDestroy(&pointIS)); 4490 PetscCall(PetscFree4(u, u_t, elemVec, a)); 4491 } 4492 end: 4493 PetscCall(DMDestroy(&plex)); 4494 PetscCall(DMDestroy(&plexA)); 4495 PetscFunctionReturn(0); 4496 } 4497 4498 PetscErrorCode DMPlexComputeBdResidualSingle(DM dm, PetscReal t, PetscWeakForm wf, PetscFormKey key, Vec locX, Vec locX_t, Vec locF) 4499 { 4500 DMField coordField; 4501 DMLabel depthLabel; 4502 IS facetIS; 4503 PetscInt dim; 4504 4505 PetscFunctionBegin; 4506 PetscCall(DMGetDimension(dm, &dim)); 4507 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 4508 PetscCall(DMLabelGetStratumIS(depthLabel, dim-1, &facetIS)); 4509 PetscCall(DMGetCoordinateField(dm, &coordField)); 4510 PetscCall(DMPlexComputeBdResidual_Single_Internal(dm, t, wf, key, locX, locX_t, locF, coordField, facetIS)); 4511 PetscCall(ISDestroy(&facetIS)); 4512 PetscFunctionReturn(0); 4513 } 4514 4515 PetscErrorCode DMPlexComputeBdResidual_Internal(DM dm, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user) 4516 { 4517 PetscDS prob; 4518 PetscInt numBd, bd; 4519 DMField coordField = NULL; 4520 IS facetIS = NULL; 4521 DMLabel depthLabel; 4522 PetscInt dim; 4523 4524 PetscFunctionBegin; 4525 PetscCall(DMGetDS(dm, &prob)); 4526 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 4527 PetscCall(DMGetDimension(dm, &dim)); 4528 PetscCall(DMLabelGetStratumIS(depthLabel,dim - 1,&facetIS)); 4529 PetscCall(PetscDSGetNumBoundary(prob, &numBd)); 4530 for (bd = 0; bd < numBd; ++bd) { 4531 PetscWeakForm wf; 4532 DMBoundaryConditionType type; 4533 DMLabel label; 4534 const PetscInt *values; 4535 PetscInt field, numValues, v; 4536 PetscObject obj; 4537 PetscClassId id; 4538 PetscFormKey key; 4539 4540 PetscCall(PetscDSGetBoundary(prob, bd, &wf, &type, NULL, &label, &numValues, &values, &field, NULL, NULL, NULL, NULL, NULL)); 4541 PetscCall(PetscDSGetDiscretization(prob, field, &obj)); 4542 PetscCall(PetscObjectGetClassId(obj, &id)); 4543 if ((id != PETSCFE_CLASSID) || (type & DM_BC_ESSENTIAL)) continue; 4544 if (!facetIS) { 4545 DMLabel depthLabel; 4546 PetscInt dim; 4547 4548 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 4549 PetscCall(DMGetDimension(dm, &dim)); 4550 PetscCall(DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS)); 4551 } 4552 PetscCall(DMGetCoordinateField(dm, &coordField)); 4553 for (v = 0; v < numValues; ++v) { 4554 key.label = label; 4555 key.value = values[v]; 4556 key.field = field; 4557 key.part = 0; 4558 PetscCall(DMPlexComputeBdResidual_Single_Internal(dm, t, wf, key, locX, locX_t, locF, coordField, facetIS)); 4559 } 4560 } 4561 PetscCall(ISDestroy(&facetIS)); 4562 PetscFunctionReturn(0); 4563 } 4564 4565 PetscErrorCode DMPlexComputeResidual_Internal(DM dm, PetscFormKey key, IS cellIS, PetscReal time, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user) 4566 { 4567 DM_Plex *mesh = (DM_Plex *) dm->data; 4568 const char *name = "Residual"; 4569 DM dmAux = NULL; 4570 DM dmGrad = NULL; 4571 DMLabel ghostLabel = NULL; 4572 PetscDS ds = NULL; 4573 PetscDS dsAux = NULL; 4574 PetscSection section = NULL; 4575 PetscBool useFEM = PETSC_FALSE; 4576 PetscBool useFVM = PETSC_FALSE; 4577 PetscBool isImplicit = (locX_t || time == PETSC_MIN_REAL) ? PETSC_TRUE : PETSC_FALSE; 4578 PetscFV fvm = NULL; 4579 PetscFVCellGeom *cgeomFVM = NULL; 4580 PetscFVFaceGeom *fgeomFVM = NULL; 4581 DMField coordField = NULL; 4582 Vec locA, cellGeometryFVM = NULL, faceGeometryFVM = NULL, grad, locGrad = NULL; 4583 PetscScalar *u = NULL, *u_t, *a, *uL, *uR; 4584 IS chunkIS; 4585 const PetscInt *cells; 4586 PetscInt cStart, cEnd, numCells; 4587 PetscInt Nf, f, totDim, totDimAux, numChunks, cellChunkSize, faceChunkSize, chunk, fStart, fEnd; 4588 PetscInt maxDegree = PETSC_MAX_INT; 4589 PetscQuadrature affineQuad = NULL, *quads = NULL; 4590 PetscFEGeom *affineGeom = NULL, **geoms = NULL; 4591 4592 PetscFunctionBegin; 4593 PetscCall(PetscLogEventBegin(DMPLEX_ResidualFEM,dm,0,0,0)); 4594 /* TODO The places where we have to use isFE are probably the member functions for the PetscDisc class */ 4595 /* TODO The FVM geometry is over-manipulated. Make the precalc functions return exactly what we need */ 4596 /* FEM+FVM */ 4597 PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 4598 PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 4599 /* 1: Get sizes from dm and dmAux */ 4600 PetscCall(DMGetLocalSection(dm, §ion)); 4601 PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 4602 PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &ds)); 4603 PetscCall(PetscDSGetNumFields(ds, &Nf)); 4604 PetscCall(PetscDSGetTotalDimension(ds, &totDim)); 4605 PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &locA)); 4606 if (locA) { 4607 PetscInt subcell; 4608 PetscCall(VecGetDM(locA, &dmAux)); 4609 PetscCall(DMGetEnclosurePoint(dmAux, dm, DM_ENC_UNKNOWN, cStart, &subcell)); 4610 PetscCall(DMGetCellDS(dmAux, subcell, &dsAux)); 4611 PetscCall(PetscDSGetTotalDimension(dsAux, &totDimAux)); 4612 } 4613 /* 2: Get geometric data */ 4614 for (f = 0; f < Nf; ++f) { 4615 PetscObject obj; 4616 PetscClassId id; 4617 PetscBool fimp; 4618 4619 PetscCall(PetscDSGetImplicit(ds, f, &fimp)); 4620 if (isImplicit != fimp) continue; 4621 PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 4622 PetscCall(PetscObjectGetClassId(obj, &id)); 4623 if (id == PETSCFE_CLASSID) {useFEM = PETSC_TRUE;} 4624 if (id == PETSCFV_CLASSID) {useFVM = PETSC_TRUE; fvm = (PetscFV) obj;} 4625 } 4626 if (useFEM) { 4627 PetscCall(DMGetCoordinateField(dm, &coordField)); 4628 PetscCall(DMFieldGetDegree(coordField,cellIS,NULL,&maxDegree)); 4629 if (maxDegree <= 1) { 4630 PetscCall(DMFieldCreateDefaultQuadrature(coordField,cellIS,&affineQuad)); 4631 if (affineQuad) { 4632 PetscCall(DMSNESGetFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom)); 4633 } 4634 } else { 4635 PetscCall(PetscCalloc2(Nf,&quads,Nf,&geoms)); 4636 for (f = 0; f < Nf; ++f) { 4637 PetscObject obj; 4638 PetscClassId id; 4639 PetscBool fimp; 4640 4641 PetscCall(PetscDSGetImplicit(ds, f, &fimp)); 4642 if (isImplicit != fimp) continue; 4643 PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 4644 PetscCall(PetscObjectGetClassId(obj, &id)); 4645 if (id == PETSCFE_CLASSID) { 4646 PetscFE fe = (PetscFE) obj; 4647 4648 PetscCall(PetscFEGetQuadrature(fe, &quads[f])); 4649 PetscCall(PetscObjectReference((PetscObject)quads[f])); 4650 PetscCall(DMSNESGetFEGeom(coordField,cellIS,quads[f],PETSC_FALSE,&geoms[f])); 4651 } 4652 } 4653 } 4654 } 4655 if (useFVM) { 4656 PetscCall(DMPlexGetGeometryFVM(dm, &faceGeometryFVM, &cellGeometryFVM, NULL)); 4657 PetscCall(VecGetArrayRead(faceGeometryFVM, (const PetscScalar **) &fgeomFVM)); 4658 PetscCall(VecGetArrayRead(cellGeometryFVM, (const PetscScalar **) &cgeomFVM)); 4659 /* Reconstruct and limit cell gradients */ 4660 PetscCall(DMPlexGetGradientDM(dm, fvm, &dmGrad)); 4661 if (dmGrad) { 4662 PetscCall(DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd)); 4663 PetscCall(DMGetGlobalVector(dmGrad, &grad)); 4664 PetscCall(DMPlexReconstructGradients_Internal(dm, fvm, fStart, fEnd, faceGeometryFVM, cellGeometryFVM, locX, grad)); 4665 /* Communicate gradient values */ 4666 PetscCall(DMGetLocalVector(dmGrad, &locGrad)); 4667 PetscCall(DMGlobalToLocalBegin(dmGrad, grad, INSERT_VALUES, locGrad)); 4668 PetscCall(DMGlobalToLocalEnd(dmGrad, grad, INSERT_VALUES, locGrad)); 4669 PetscCall(DMRestoreGlobalVector(dmGrad, &grad)); 4670 } 4671 /* Handle non-essential (e.g. outflow) boundary values */ 4672 PetscCall(DMPlexInsertBoundaryValues(dm, PETSC_FALSE, locX, time, faceGeometryFVM, cellGeometryFVM, locGrad)); 4673 } 4674 /* Loop over chunks */ 4675 if (useFEM) PetscCall(ISCreate(PETSC_COMM_SELF, &chunkIS)); 4676 numCells = cEnd - cStart; 4677 numChunks = 1; 4678 cellChunkSize = numCells/numChunks; 4679 faceChunkSize = (fEnd - fStart)/numChunks; 4680 numChunks = PetscMin(1,numCells); 4681 for (chunk = 0; chunk < numChunks; ++chunk) { 4682 PetscScalar *elemVec, *fluxL, *fluxR; 4683 PetscReal *vol; 4684 PetscFVFaceGeom *fgeom; 4685 PetscInt cS = cStart+chunk*cellChunkSize, cE = PetscMin(cS+cellChunkSize, cEnd), numCells = cE - cS, c; 4686 PetscInt fS = fStart+chunk*faceChunkSize, fE = PetscMin(fS+faceChunkSize, fEnd), numFaces = 0, face; 4687 4688 /* Extract field coefficients */ 4689 if (useFEM) { 4690 PetscCall(ISGetPointSubrange(chunkIS, cS, cE, cells)); 4691 PetscCall(DMPlexGetCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a)); 4692 PetscCall(DMGetWorkArray(dm, numCells*totDim, MPIU_SCALAR, &elemVec)); 4693 PetscCall(PetscArrayzero(elemVec, numCells*totDim)); 4694 } 4695 if (useFVM) { 4696 PetscCall(DMPlexGetFaceFields(dm, fS, fE, locX, locX_t, faceGeometryFVM, cellGeometryFVM, locGrad, &numFaces, &uL, &uR)); 4697 PetscCall(DMPlexGetFaceGeometry(dm, fS, fE, faceGeometryFVM, cellGeometryFVM, &numFaces, &fgeom, &vol)); 4698 PetscCall(DMGetWorkArray(dm, numFaces*totDim, MPIU_SCALAR, &fluxL)); 4699 PetscCall(DMGetWorkArray(dm, numFaces*totDim, MPIU_SCALAR, &fluxR)); 4700 PetscCall(PetscArrayzero(fluxL, numFaces*totDim)); 4701 PetscCall(PetscArrayzero(fluxR, numFaces*totDim)); 4702 } 4703 /* TODO We will interlace both our field coefficients (u, u_t, uL, uR, etc.) and our output (elemVec, fL, fR). I think this works */ 4704 /* Loop over fields */ 4705 for (f = 0; f < Nf; ++f) { 4706 PetscObject obj; 4707 PetscClassId id; 4708 PetscBool fimp; 4709 PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset; 4710 4711 key.field = f; 4712 PetscCall(PetscDSGetImplicit(ds, f, &fimp)); 4713 if (isImplicit != fimp) continue; 4714 PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 4715 PetscCall(PetscObjectGetClassId(obj, &id)); 4716 if (id == PETSCFE_CLASSID) { 4717 PetscFE fe = (PetscFE) obj; 4718 PetscFEGeom *geom = affineGeom ? affineGeom : geoms[f]; 4719 PetscFEGeom *chunkGeom = NULL; 4720 PetscQuadrature quad = affineQuad ? affineQuad : quads[f]; 4721 PetscInt Nq, Nb; 4722 4723 PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 4724 PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL)); 4725 PetscCall(PetscFEGetDimension(fe, &Nb)); 4726 blockSize = Nb; 4727 batchSize = numBlocks * blockSize; 4728 PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 4729 numChunks = numCells / (numBatches*batchSize); 4730 Ne = numChunks*numBatches*batchSize; 4731 Nr = numCells % (numBatches*batchSize); 4732 offset = numCells - Nr; 4733 /* Integrate FE residual to get elemVec (need fields at quadrature points) */ 4734 /* 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) */ 4735 PetscCall(PetscFEGeomGetChunk(geom,0,offset,&chunkGeom)); 4736 PetscCall(PetscFEIntegrateResidual(ds, key, Ne, chunkGeom, u, u_t, dsAux, a, t, elemVec)); 4737 PetscCall(PetscFEGeomGetChunk(geom,offset,numCells,&chunkGeom)); 4738 PetscCall(PetscFEIntegrateResidual(ds, key, Nr, chunkGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, dsAux, &a[offset*totDimAux], t, &elemVec[offset*totDim])); 4739 PetscCall(PetscFEGeomRestoreChunk(geom,offset,numCells,&chunkGeom)); 4740 } else if (id == PETSCFV_CLASSID) { 4741 PetscFV fv = (PetscFV) obj; 4742 4743 Ne = numFaces; 4744 /* Riemann solve over faces (need fields at face centroids) */ 4745 /* We need to evaluate FE fields at those coordinates */ 4746 PetscCall(PetscFVIntegrateRHSFunction(fv, ds, f, Ne, fgeom, vol, uL, uR, fluxL, fluxR)); 4747 } else SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", f); 4748 } 4749 /* Loop over domain */ 4750 if (useFEM) { 4751 /* Add elemVec to locX */ 4752 for (c = cS; c < cE; ++c) { 4753 const PetscInt cell = cells ? cells[c] : c; 4754 const PetscInt cind = c - cStart; 4755 4756 if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, name, totDim, &elemVec[cind*totDim])); 4757 if (ghostLabel) { 4758 PetscInt ghostVal; 4759 4760 PetscCall(DMLabelGetValue(ghostLabel,cell,&ghostVal)); 4761 if (ghostVal > 0) continue; 4762 } 4763 PetscCall(DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind*totDim], ADD_ALL_VALUES)); 4764 } 4765 } 4766 if (useFVM) { 4767 PetscScalar *fa; 4768 PetscInt iface; 4769 4770 PetscCall(VecGetArray(locF, &fa)); 4771 for (f = 0; f < Nf; ++f) { 4772 PetscFV fv; 4773 PetscObject obj; 4774 PetscClassId id; 4775 PetscInt foff, pdim; 4776 4777 PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 4778 PetscCall(PetscDSGetFieldOffset(ds, f, &foff)); 4779 PetscCall(PetscObjectGetClassId(obj, &id)); 4780 if (id != PETSCFV_CLASSID) continue; 4781 fv = (PetscFV) obj; 4782 PetscCall(PetscFVGetNumComponents(fv, &pdim)); 4783 /* Accumulate fluxes to cells */ 4784 for (face = fS, iface = 0; face < fE; ++face) { 4785 const PetscInt *scells; 4786 PetscScalar *fL = NULL, *fR = NULL; 4787 PetscInt ghost, d, nsupp, nchild; 4788 4789 PetscCall(DMLabelGetValue(ghostLabel, face, &ghost)); 4790 PetscCall(DMPlexGetSupportSize(dm, face, &nsupp)); 4791 PetscCall(DMPlexGetTreeChildren(dm, face, &nchild, NULL)); 4792 if (ghost >= 0 || nsupp > 2 || nchild > 0) continue; 4793 PetscCall(DMPlexGetSupport(dm, face, &scells)); 4794 PetscCall(DMLabelGetValue(ghostLabel,scells[0],&ghost)); 4795 if (ghost <= 0) PetscCall(DMPlexPointLocalFieldRef(dm, scells[0], f, fa, &fL)); 4796 PetscCall(DMLabelGetValue(ghostLabel,scells[1],&ghost)); 4797 if (ghost <= 0) PetscCall(DMPlexPointLocalFieldRef(dm, scells[1], f, fa, &fR)); 4798 for (d = 0; d < pdim; ++d) { 4799 if (fL) fL[d] -= fluxL[iface*totDim+foff+d]; 4800 if (fR) fR[d] += fluxR[iface*totDim+foff+d]; 4801 } 4802 ++iface; 4803 } 4804 } 4805 PetscCall(VecRestoreArray(locF, &fa)); 4806 } 4807 /* Handle time derivative */ 4808 if (locX_t) { 4809 PetscScalar *x_t, *fa; 4810 4811 PetscCall(VecGetArray(locF, &fa)); 4812 PetscCall(VecGetArray(locX_t, &x_t)); 4813 for (f = 0; f < Nf; ++f) { 4814 PetscFV fv; 4815 PetscObject obj; 4816 PetscClassId id; 4817 PetscInt pdim, d; 4818 4819 PetscCall(PetscDSGetDiscretization(ds, f, &obj)); 4820 PetscCall(PetscObjectGetClassId(obj, &id)); 4821 if (id != PETSCFV_CLASSID) continue; 4822 fv = (PetscFV) obj; 4823 PetscCall(PetscFVGetNumComponents(fv, &pdim)); 4824 for (c = cS; c < cE; ++c) { 4825 const PetscInt cell = cells ? cells[c] : c; 4826 PetscScalar *u_t, *r; 4827 4828 if (ghostLabel) { 4829 PetscInt ghostVal; 4830 4831 PetscCall(DMLabelGetValue(ghostLabel, cell, &ghostVal)); 4832 if (ghostVal > 0) continue; 4833 } 4834 PetscCall(DMPlexPointLocalFieldRead(dm, cell, f, x_t, &u_t)); 4835 PetscCall(DMPlexPointLocalFieldRef(dm, cell, f, fa, &r)); 4836 for (d = 0; d < pdim; ++d) r[d] += u_t[d]; 4837 } 4838 } 4839 PetscCall(VecRestoreArray(locX_t, &x_t)); 4840 PetscCall(VecRestoreArray(locF, &fa)); 4841 } 4842 if (useFEM) { 4843 PetscCall(DMPlexRestoreCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a)); 4844 PetscCall(DMRestoreWorkArray(dm, numCells*totDim, MPIU_SCALAR, &elemVec)); 4845 } 4846 if (useFVM) { 4847 PetscCall(DMPlexRestoreFaceFields(dm, fS, fE, locX, locX_t, faceGeometryFVM, cellGeometryFVM, locGrad, &numFaces, &uL, &uR)); 4848 PetscCall(DMPlexRestoreFaceGeometry(dm, fS, fE, faceGeometryFVM, cellGeometryFVM, &numFaces, &fgeom, &vol)); 4849 PetscCall(DMRestoreWorkArray(dm, numFaces*totDim, MPIU_SCALAR, &fluxL)); 4850 PetscCall(DMRestoreWorkArray(dm, numFaces*totDim, MPIU_SCALAR, &fluxR)); 4851 if (dmGrad) PetscCall(DMRestoreLocalVector(dmGrad, &locGrad)); 4852 } 4853 } 4854 if (useFEM) PetscCall(ISDestroy(&chunkIS)); 4855 PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 4856 4857 if (useFEM) { 4858 PetscCall(DMPlexComputeBdResidual_Internal(dm, locX, locX_t, t, locF, user)); 4859 4860 if (maxDegree <= 1) { 4861 PetscCall(DMSNESRestoreFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom)); 4862 PetscCall(PetscQuadratureDestroy(&affineQuad)); 4863 } else { 4864 for (f = 0; f < Nf; ++f) { 4865 PetscCall(DMSNESRestoreFEGeom(coordField,cellIS,quads[f],PETSC_FALSE,&geoms[f])); 4866 PetscCall(PetscQuadratureDestroy(&quads[f])); 4867 } 4868 PetscCall(PetscFree2(quads,geoms)); 4869 } 4870 } 4871 4872 /* FEM */ 4873 /* 1: Get sizes from dm and dmAux */ 4874 /* 2: Get geometric data */ 4875 /* 3: Handle boundary values */ 4876 /* 4: Loop over domain */ 4877 /* Extract coefficients */ 4878 /* Loop over fields */ 4879 /* Set tiling for FE*/ 4880 /* Integrate FE residual to get elemVec */ 4881 /* Loop over subdomain */ 4882 /* Loop over quad points */ 4883 /* Transform coords to real space */ 4884 /* Evaluate field and aux fields at point */ 4885 /* Evaluate residual at point */ 4886 /* Transform residual to real space */ 4887 /* Add residual to elemVec */ 4888 /* Loop over domain */ 4889 /* Add elemVec to locX */ 4890 4891 /* FVM */ 4892 /* Get geometric data */ 4893 /* If using gradients */ 4894 /* Compute gradient data */ 4895 /* Loop over domain faces */ 4896 /* Count computational faces */ 4897 /* Reconstruct cell gradient */ 4898 /* Loop over domain cells */ 4899 /* Limit cell gradients */ 4900 /* Handle boundary values */ 4901 /* Loop over domain faces */ 4902 /* Read out field, centroid, normal, volume for each side of face */ 4903 /* Riemann solve over faces */ 4904 /* Loop over domain faces */ 4905 /* Accumulate fluxes to cells */ 4906 /* TODO Change printFEM to printDisc here */ 4907 if (mesh->printFEM) { 4908 Vec locFbc; 4909 PetscInt pStart, pEnd, p, maxDof; 4910 PetscScalar *zeroes; 4911 4912 PetscCall(VecDuplicate(locF,&locFbc)); 4913 PetscCall(VecCopy(locF,locFbc)); 4914 PetscCall(PetscSectionGetChart(section,&pStart,&pEnd)); 4915 PetscCall(PetscSectionGetMaxDof(section,&maxDof)); 4916 PetscCall(PetscCalloc1(maxDof,&zeroes)); 4917 for (p = pStart; p < pEnd; p++) { 4918 PetscCall(VecSetValuesSection(locFbc,section,p,zeroes,INSERT_BC_VALUES)); 4919 } 4920 PetscCall(PetscFree(zeroes)); 4921 PetscCall(DMPrintLocalVec(dm, name, mesh->printTol, locFbc)); 4922 PetscCall(VecDestroy(&locFbc)); 4923 } 4924 PetscCall(PetscLogEventEnd(DMPLEX_ResidualFEM,dm,0,0,0)); 4925 PetscFunctionReturn(0); 4926 } 4927 4928 /* 4929 1) Allow multiple kernels for BdResidual for hybrid DS 4930 4931 DONE 2) Get out dsAux for either side at the same time as cohesive cell dsAux 4932 4933 DONE 3) Change DMGetCellFields() to get different aux data a[] for each side 4934 - I think I just need to replace a[] with the closure from each face 4935 4936 4) Run both kernels for each non-hybrid field with correct dsAux, and then hybrid field as before 4937 */ 4938 PetscErrorCode DMPlexComputeResidual_Hybrid_Internal(DM dm, PetscFormKey key[], IS cellIS, PetscReal time, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user) 4939 { 4940 DM_Plex *mesh = (DM_Plex *) dm->data; 4941 const char *name = "Hybrid Residual"; 4942 DM dmAux[3] = {NULL, NULL, NULL}; 4943 DMLabel ghostLabel = NULL; 4944 PetscDS ds = NULL; 4945 PetscDS dsAux[3] = {NULL, NULL, NULL}; 4946 Vec locA[3] = {NULL, NULL, NULL}; 4947 PetscSection section = NULL; 4948 DMField coordField = NULL; 4949 PetscScalar *u = NULL, *u_t, *a[3]; 4950 PetscScalar *elemVec; 4951 IS chunkIS; 4952 const PetscInt *cells; 4953 PetscInt *faces; 4954 PetscInt cStart, cEnd, numCells; 4955 PetscInt Nf, f, totDim, totDimAux[3], numChunks, cellChunkSize, chunk; 4956 PetscInt maxDegree = PETSC_MAX_INT; 4957 PetscQuadrature affineQuad = NULL, *quads = NULL; 4958 PetscFEGeom *affineGeom = NULL, **geoms = NULL; 4959 4960 PetscFunctionBegin; 4961 if ((key[0].label == key[1].label) && (key[0].value == key[1].value) && (key[0].part == key[1].part)) { 4962 const char *name; 4963 PetscCall(PetscObjectGetName((PetscObject) key[0].label, &name)); 4964 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Form keys for each side of a cohesive surface must be different (%s, %D, %D)", name, key[0].value, key[0].part); 4965 } 4966 PetscCall(PetscLogEventBegin(DMPLEX_ResidualFEM,dm,0,0,0)); 4967 /* TODO The places where we have to use isFE are probably the member functions for the PetscDisc class */ 4968 /* FEM */ 4969 PetscCall(ISGetLocalSize(cellIS, &numCells)); 4970 PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 4971 /* 1: Get sizes from dm and dmAux */ 4972 PetscCall(DMGetSection(dm, §ion)); 4973 PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 4974 PetscCall(DMGetCellDS(dm, cStart, &ds)); 4975 PetscCall(PetscDSGetNumFields(ds, &Nf)); 4976 PetscCall(PetscDSGetTotalDimension(ds, &totDim)); 4977 PetscCall(DMGetAuxiliaryVec(dm, key[2].label, key[2].value, key[2].part, &locA[2])); 4978 if (locA[2]) { 4979 PetscCall(VecGetDM(locA[2], &dmAux[2])); 4980 PetscCall(DMGetCellDS(dmAux[2], cStart, &dsAux[2])); 4981 PetscCall(PetscDSGetTotalDimension(dsAux[2], &totDimAux[2])); 4982 { 4983 const PetscInt *cone; 4984 PetscInt c; 4985 4986 PetscCall(DMPlexGetCone(dm, cStart, &cone)); 4987 for (c = 0; c < 2; ++c) { 4988 const PetscInt *support; 4989 PetscInt ssize, s; 4990 4991 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 4992 PetscCall(DMPlexGetSupportSize(dm, cone[c], &ssize)); 4993 PetscCheck(ssize == 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %D from cell %D has support size %D != 2", cone[c], cStart, ssize); 4994 if (support[0] == cStart) s = 1; 4995 else if (support[1] == cStart) s = 0; 4996 else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %D does not have cell %D in its support", cone[c], cStart); 4997 PetscCall(DMGetAuxiliaryVec(dm, key[c].label, key[c].value, key[c].part, &locA[c])); 4998 if (locA[c]) PetscCall(VecGetDM(locA[c], &dmAux[c])); 4999 else {dmAux[c] = dmAux[2];} 5000 PetscCall(DMGetCellDS(dmAux[c], support[s], &dsAux[c])); 5001 PetscCall(PetscDSGetTotalDimension(dsAux[c], &totDimAux[c])); 5002 } 5003 } 5004 } 5005 /* 2: Setup geometric data */ 5006 PetscCall(DMGetCoordinateField(dm, &coordField)); 5007 PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 5008 if (maxDegree > 1) { 5009 PetscCall(PetscCalloc2(Nf, &quads, Nf, &geoms)); 5010 for (f = 0; f < Nf; ++f) { 5011 PetscFE fe; 5012 5013 PetscCall(PetscDSGetDiscretization(ds, f, (PetscObject *) &fe)); 5014 if (fe) { 5015 PetscCall(PetscFEGetQuadrature(fe, &quads[f])); 5016 PetscCall(PetscObjectReference((PetscObject) quads[f])); 5017 } 5018 } 5019 } 5020 /* Loop over chunks */ 5021 cellChunkSize = numCells; 5022 numChunks = !numCells ? 0 : PetscCeilReal(((PetscReal) numCells)/cellChunkSize); 5023 PetscCall(PetscCalloc1(2*cellChunkSize, &faces)); 5024 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, cellChunkSize, faces, PETSC_USE_POINTER, &chunkIS)); 5025 /* Extract field coefficients */ 5026 /* NOTE This needs the end cap faces to have identical orientations */ 5027 PetscCall(DMPlexGetCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2])); 5028 PetscCall(DMPlexGetHybridAuxFields(dm, dmAux, dsAux, cellIS, locA, a)); 5029 PetscCall(DMGetWorkArray(dm, cellChunkSize*totDim, MPIU_SCALAR, &elemVec)); 5030 for (chunk = 0; chunk < numChunks; ++chunk) { 5031 PetscInt cS = cStart+chunk*cellChunkSize, cE = PetscMin(cS+cellChunkSize, cEnd), numCells = cE - cS, c; 5032 5033 PetscCall(PetscMemzero(elemVec, cellChunkSize*totDim * sizeof(PetscScalar))); 5034 /* Get faces */ 5035 for (c = cS; c < cE; ++c) { 5036 const PetscInt cell = cells ? cells[c] : c; 5037 const PetscInt *cone; 5038 PetscCall(DMPlexGetCone(dm, cell, &cone)); 5039 faces[(c-cS)*2+0] = cone[0]; 5040 faces[(c-cS)*2+1] = cone[1]; 5041 } 5042 PetscCall(ISGeneralSetIndices(chunkIS, cellChunkSize, faces, PETSC_USE_POINTER)); 5043 /* Get geometric data */ 5044 if (maxDegree <= 1) { 5045 if (!affineQuad) PetscCall(DMFieldCreateDefaultQuadrature(coordField, chunkIS, &affineQuad)); 5046 if (affineQuad) PetscCall(DMSNESGetFEGeom(coordField, chunkIS, affineQuad, PETSC_TRUE, &affineGeom)); 5047 } else { 5048 for (f = 0; f < Nf; ++f) { 5049 if (quads[f]) PetscCall(DMSNESGetFEGeom(coordField, chunkIS, quads[f], PETSC_TRUE, &geoms[f])); 5050 } 5051 } 5052 /* Loop over fields */ 5053 for (f = 0; f < Nf; ++f) { 5054 PetscFE fe; 5055 PetscFEGeom *geom = affineGeom ? affineGeom : geoms[f]; 5056 PetscFEGeom *chunkGeom = NULL, *remGeom = NULL; 5057 PetscQuadrature quad = affineQuad ? affineQuad : quads[f]; 5058 PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset, Nq, Nb; 5059 PetscBool isCohesiveField; 5060 5061 PetscCall(PetscDSGetDiscretization(ds, f, (PetscObject *) &fe)); 5062 if (!fe) continue; 5063 PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 5064 PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL)); 5065 PetscCall(PetscFEGetDimension(fe, &Nb)); 5066 blockSize = Nb; 5067 batchSize = numBlocks * blockSize; 5068 PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 5069 numChunks = numCells / (numBatches*batchSize); 5070 Ne = numChunks*numBatches*batchSize; 5071 Nr = numCells % (numBatches*batchSize); 5072 offset = numCells - Nr; 5073 PetscCall(PetscFEGeomGetChunk(geom,0,offset,&chunkGeom)); 5074 PetscCall(PetscFEGeomGetChunk(geom,offset,numCells,&remGeom)); 5075 PetscCall(PetscDSGetCohesive(ds, f, &isCohesiveField)); 5076 chunkGeom->isCohesive = remGeom->isCohesive = PETSC_TRUE; 5077 key[0].field = f; 5078 key[1].field = f; 5079 key[2].field = f; 5080 PetscCall(PetscFEIntegrateHybridResidual(ds, key[0], 0, Ne, chunkGeom, u, u_t, dsAux[0], a[0], t, elemVec)); 5081 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])); 5082 PetscCall(PetscFEIntegrateHybridResidual(ds, key[1], 1, Ne, chunkGeom, u, u_t, dsAux[1], a[1], t, elemVec)); 5083 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])); 5084 PetscCall(PetscFEIntegrateHybridResidual(ds, key[2], 2, Ne, chunkGeom, u, u_t, dsAux[2], a[2], t, elemVec)); 5085 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])); 5086 PetscCall(PetscFEGeomRestoreChunk(geom,offset,numCells,&remGeom)); 5087 PetscCall(PetscFEGeomRestoreChunk(geom,0,offset,&chunkGeom)); 5088 } 5089 /* Add elemVec to locX */ 5090 for (c = cS; c < cE; ++c) { 5091 const PetscInt cell = cells ? cells[c] : c; 5092 const PetscInt cind = c - cStart; 5093 5094 if (mesh->printFEM > 1) PetscCall(DMPrintCellVector(cell, name, totDim, &elemVec[cind*totDim])); 5095 if (ghostLabel) { 5096 PetscInt ghostVal; 5097 5098 PetscCall(DMLabelGetValue(ghostLabel,cell,&ghostVal)); 5099 if (ghostVal > 0) continue; 5100 } 5101 PetscCall(DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind*totDim], ADD_ALL_VALUES)); 5102 } 5103 } 5104 PetscCall(DMPlexRestoreCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2])); 5105 PetscCall(DMPlexRestoreHybridAuxFields(dmAux, dsAux, cellIS, locA, a)); 5106 PetscCall(DMRestoreWorkArray(dm, numCells*totDim, MPIU_SCALAR, &elemVec)); 5107 PetscCall(PetscFree(faces)); 5108 PetscCall(ISDestroy(&chunkIS)); 5109 PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 5110 if (maxDegree <= 1) { 5111 PetscCall(DMSNESRestoreFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom)); 5112 PetscCall(PetscQuadratureDestroy(&affineQuad)); 5113 } else { 5114 for (f = 0; f < Nf; ++f) { 5115 if (geoms) PetscCall(DMSNESRestoreFEGeom(coordField,cellIS,quads[f],PETSC_FALSE,&geoms[f])); 5116 if (quads) PetscCall(PetscQuadratureDestroy(&quads[f])); 5117 } 5118 PetscCall(PetscFree2(quads,geoms)); 5119 } 5120 PetscCall(PetscLogEventEnd(DMPLEX_ResidualFEM,dm,0,0,0)); 5121 PetscFunctionReturn(0); 5122 } 5123 5124 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) 5125 { 5126 DM_Plex *mesh = (DM_Plex *) dm->data; 5127 DM plex = NULL, plexA = NULL, tdm; 5128 DMEnclosureType encAux; 5129 PetscDS prob, probAux = NULL; 5130 PetscSection section, sectionAux = NULL; 5131 PetscSection globalSection; 5132 Vec locA = NULL, tv; 5133 PetscScalar *u = NULL, *u_t = NULL, *a = NULL, *elemMat = NULL; 5134 PetscInt v; 5135 PetscInt Nf, totDim, totDimAux = 0; 5136 PetscBool transform; 5137 5138 PetscFunctionBegin; 5139 PetscCall(DMConvert(dm, DMPLEX, &plex)); 5140 PetscCall(DMHasBasisTransform(dm, &transform)); 5141 PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm)); 5142 PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 5143 PetscCall(DMGetLocalSection(dm, §ion)); 5144 PetscCall(DMGetDS(dm, &prob)); 5145 PetscCall(PetscDSGetNumFields(prob, &Nf)); 5146 PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 5147 PetscCall(DMGetAuxiliaryVec(dm, label, values[0], 0, &locA)); 5148 if (locA) { 5149 DM dmAux; 5150 5151 PetscCall(VecGetDM(locA, &dmAux)); 5152 PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 5153 PetscCall(DMConvert(dmAux, DMPLEX, &plexA)); 5154 PetscCall(DMGetDS(plexA, &probAux)); 5155 PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 5156 PetscCall(DMGetLocalSection(plexA, §ionAux)); 5157 } 5158 5159 PetscCall(DMGetGlobalSection(dm, &globalSection)); 5160 for (v = 0; v < numValues; ++v) { 5161 PetscFEGeom *fgeom; 5162 PetscInt maxDegree; 5163 PetscQuadrature qGeom = NULL; 5164 IS pointIS; 5165 const PetscInt *points; 5166 PetscFormKey key; 5167 PetscInt numFaces, face, Nq; 5168 5169 key.label = label; 5170 key.value = values[v]; 5171 key.part = 0; 5172 PetscCall(DMLabelGetStratumIS(label, values[v], &pointIS)); 5173 if (!pointIS) continue; /* No points with that id on this process */ 5174 { 5175 IS isectIS; 5176 5177 /* TODO: Special cases of ISIntersect where it is quick to check a prior if one is a superset of the other */ 5178 PetscCall(ISIntersect_Caching_Internal(facetIS,pointIS,&isectIS)); 5179 PetscCall(ISDestroy(&pointIS)); 5180 pointIS = isectIS; 5181 } 5182 PetscCall(ISGetLocalSize(pointIS, &numFaces)); 5183 PetscCall(ISGetIndices(pointIS, &points)); 5184 PetscCall(PetscMalloc4(numFaces*totDim, &u, locX_t ? numFaces*totDim : 0, &u_t, numFaces*totDim*totDim, &elemMat, locA ? numFaces*totDimAux : 0, &a)); 5185 PetscCall(DMFieldGetDegree(coordField,pointIS,NULL,&maxDegree)); 5186 if (maxDegree <= 1) { 5187 PetscCall(DMFieldCreateDefaultQuadrature(coordField,pointIS,&qGeom)); 5188 } 5189 if (!qGeom) { 5190 PetscFE fe; 5191 5192 PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fe)); 5193 PetscCall(PetscFEGetFaceQuadrature(fe, &qGeom)); 5194 PetscCall(PetscObjectReference((PetscObject)qGeom)); 5195 } 5196 PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL)); 5197 PetscCall(DMSNESGetFEGeom(coordField,pointIS,qGeom,PETSC_TRUE,&fgeom)); 5198 for (face = 0; face < numFaces; ++face) { 5199 const PetscInt point = points[face], *support; 5200 PetscScalar *x = NULL; 5201 PetscInt i; 5202 5203 PetscCall(DMPlexGetSupport(dm, point, &support)); 5204 PetscCall(DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x)); 5205 for (i = 0; i < totDim; ++i) u[face*totDim+i] = x[i]; 5206 PetscCall(DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x)); 5207 if (locX_t) { 5208 PetscCall(DMPlexVecGetClosure(plex, section, locX_t, support[0], NULL, &x)); 5209 for (i = 0; i < totDim; ++i) u_t[face*totDim+i] = x[i]; 5210 PetscCall(DMPlexVecRestoreClosure(plex, section, locX_t, support[0], NULL, &x)); 5211 } 5212 if (locA) { 5213 PetscInt subp; 5214 PetscCall(DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp)); 5215 PetscCall(DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x)); 5216 for (i = 0; i < totDimAux; ++i) a[face*totDimAux+i] = x[i]; 5217 PetscCall(DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x)); 5218 } 5219 } 5220 PetscCall(PetscArrayzero(elemMat, numFaces*totDim*totDim)); 5221 { 5222 PetscFE fe; 5223 PetscInt Nb; 5224 /* Conforming batches */ 5225 PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize; 5226 /* Remainder */ 5227 PetscFEGeom *chunkGeom = NULL; 5228 PetscInt fieldJ, Nr, offset; 5229 5230 PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fe)); 5231 PetscCall(PetscFEGetDimension(fe, &Nb)); 5232 PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 5233 blockSize = Nb; 5234 batchSize = numBlocks * blockSize; 5235 PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 5236 numChunks = numFaces / (numBatches*batchSize); 5237 Ne = numChunks*numBatches*batchSize; 5238 Nr = numFaces % (numBatches*batchSize); 5239 offset = numFaces - Nr; 5240 PetscCall(PetscFEGeomGetChunk(fgeom,0,offset,&chunkGeom)); 5241 for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 5242 key.field = fieldI*Nf+fieldJ; 5243 PetscCall(PetscFEIntegrateBdJacobian(prob, wf, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat)); 5244 } 5245 PetscCall(PetscFEGeomGetChunk(fgeom,offset,numFaces,&chunkGeom)); 5246 for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 5247 key.field = fieldI*Nf+fieldJ; 5248 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])); 5249 } 5250 PetscCall(PetscFEGeomRestoreChunk(fgeom,offset,numFaces,&chunkGeom)); 5251 } 5252 for (face = 0; face < numFaces; ++face) { 5253 const PetscInt point = points[face], *support; 5254 5255 /* Transform to global basis before insertion in Jacobian */ 5256 PetscCall(DMPlexGetSupport(plex, point, &support)); 5257 if (transform) PetscCall(DMPlexBasisTransformPointTensor_Internal(dm, tdm, tv, support[0], PETSC_TRUE, totDim, &elemMat[face*totDim*totDim])); 5258 if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(point, "BdJacobian", totDim, totDim, &elemMat[face*totDim*totDim])); 5259 PetscCall(DMPlexMatSetClosure(plex, section, globalSection, JacP, support[0], &elemMat[face*totDim*totDim], ADD_VALUES)); 5260 } 5261 PetscCall(DMSNESRestoreFEGeom(coordField,pointIS,qGeom,PETSC_TRUE,&fgeom)); 5262 PetscCall(PetscQuadratureDestroy(&qGeom)); 5263 PetscCall(ISRestoreIndices(pointIS, &points)); 5264 PetscCall(ISDestroy(&pointIS)); 5265 PetscCall(PetscFree4(u, u_t, elemMat, a)); 5266 } 5267 if (plex) PetscCall(DMDestroy(&plex)); 5268 if (plexA) PetscCall(DMDestroy(&plexA)); 5269 PetscFunctionReturn(0); 5270 } 5271 5272 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) 5273 { 5274 DMField coordField; 5275 DMLabel depthLabel; 5276 IS facetIS; 5277 PetscInt dim; 5278 5279 PetscFunctionBegin; 5280 PetscCall(DMGetDimension(dm, &dim)); 5281 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 5282 PetscCall(DMLabelGetStratumIS(depthLabel, dim-1, &facetIS)); 5283 PetscCall(DMGetCoordinateField(dm, &coordField)); 5284 PetscCall(DMPlexComputeBdJacobian_Single_Internal(dm, t, wf, label, numValues, values, field, locX, locX_t, X_tShift, Jac, JacP, coordField, facetIS)); 5285 PetscCall(ISDestroy(&facetIS)); 5286 PetscFunctionReturn(0); 5287 } 5288 5289 PetscErrorCode DMPlexComputeBdJacobian_Internal(DM dm, Vec locX, Vec locX_t, PetscReal t, PetscReal X_tShift, Mat Jac, Mat JacP, void *user) 5290 { 5291 PetscDS prob; 5292 PetscInt dim, numBd, bd; 5293 DMLabel depthLabel; 5294 DMField coordField = NULL; 5295 IS facetIS; 5296 5297 PetscFunctionBegin; 5298 PetscCall(DMGetDS(dm, &prob)); 5299 PetscCall(DMPlexGetDepthLabel(dm, &depthLabel)); 5300 PetscCall(DMGetDimension(dm, &dim)); 5301 PetscCall(DMLabelGetStratumIS(depthLabel, dim-1, &facetIS)); 5302 PetscCall(PetscDSGetNumBoundary(prob, &numBd)); 5303 PetscCall(DMGetCoordinateField(dm, &coordField)); 5304 for (bd = 0; bd < numBd; ++bd) { 5305 PetscWeakForm wf; 5306 DMBoundaryConditionType type; 5307 DMLabel label; 5308 const PetscInt *values; 5309 PetscInt fieldI, numValues; 5310 PetscObject obj; 5311 PetscClassId id; 5312 5313 PetscCall(PetscDSGetBoundary(prob, bd, &wf, &type, NULL, &label, &numValues, &values, &fieldI, NULL, NULL, NULL, NULL, NULL)); 5314 PetscCall(PetscDSGetDiscretization(prob, fieldI, &obj)); 5315 PetscCall(PetscObjectGetClassId(obj, &id)); 5316 if ((id != PETSCFE_CLASSID) || (type & DM_BC_ESSENTIAL)) continue; 5317 PetscCall(DMPlexComputeBdJacobian_Single_Internal(dm, t, wf, label, numValues, values, fieldI, locX, locX_t, X_tShift, Jac, JacP, coordField, facetIS)); 5318 } 5319 PetscCall(ISDestroy(&facetIS)); 5320 PetscFunctionReturn(0); 5321 } 5322 5323 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) 5324 { 5325 DM_Plex *mesh = (DM_Plex *) dm->data; 5326 const char *name = "Jacobian"; 5327 DM dmAux = NULL, plex, tdm; 5328 DMEnclosureType encAux; 5329 Vec A, tv; 5330 DMField coordField; 5331 PetscDS prob, probAux = NULL; 5332 PetscSection section, globalSection, sectionAux; 5333 PetscScalar *elemMat, *elemMatP, *elemMatD, *u, *u_t, *a = NULL; 5334 const PetscInt *cells; 5335 PetscInt Nf, fieldI, fieldJ; 5336 PetscInt totDim, totDimAux, cStart, cEnd, numCells, c; 5337 PetscBool hasJac, hasPrec, hasDyn, hasFV = PETSC_FALSE, transform; 5338 5339 PetscFunctionBegin; 5340 PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM,dm,0,0,0)); 5341 PetscCall(ISGetLocalSize(cellIS, &numCells)); 5342 PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 5343 PetscCall(DMHasBasisTransform(dm, &transform)); 5344 PetscCall(DMGetBasisTransformDM_Internal(dm, &tdm)); 5345 PetscCall(DMGetBasisTransformVec_Internal(dm, &tv)); 5346 PetscCall(DMGetLocalSection(dm, §ion)); 5347 PetscCall(DMGetGlobalSection(dm, &globalSection)); 5348 PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob)); 5349 PetscCall(PetscDSGetNumFields(prob, &Nf)); 5350 PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 5351 PetscCall(PetscDSHasJacobian(prob, &hasJac)); 5352 PetscCall(PetscDSHasJacobianPreconditioner(prob, &hasPrec)); 5353 /* user passed in the same matrix, avoid double contributions and 5354 only assemble the Jacobian */ 5355 if (hasJac && Jac == JacP) hasPrec = PETSC_FALSE; 5356 PetscCall(PetscDSHasDynamicJacobian(prob, &hasDyn)); 5357 hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE; 5358 PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &A)); 5359 if (A) { 5360 PetscCall(VecGetDM(A, &dmAux)); 5361 PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 5362 PetscCall(DMConvert(dmAux, DMPLEX, &plex)); 5363 PetscCall(DMGetLocalSection(plex, §ionAux)); 5364 PetscCall(DMGetDS(dmAux, &probAux)); 5365 PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 5366 } 5367 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)); 5368 if (dmAux) PetscCall(PetscMalloc1(numCells*totDimAux, &a)); 5369 PetscCall(DMGetCoordinateField(dm, &coordField)); 5370 for (c = cStart; c < cEnd; ++c) { 5371 const PetscInt cell = cells ? cells[c] : c; 5372 const PetscInt cind = c - cStart; 5373 PetscScalar *x = NULL, *x_t = NULL; 5374 PetscInt i; 5375 5376 PetscCall(DMPlexVecGetClosure(dm, section, X, cell, NULL, &x)); 5377 for (i = 0; i < totDim; ++i) u[cind*totDim+i] = x[i]; 5378 PetscCall(DMPlexVecRestoreClosure(dm, section, X, cell, NULL, &x)); 5379 if (X_t) { 5380 PetscCall(DMPlexVecGetClosure(dm, section, X_t, cell, NULL, &x_t)); 5381 for (i = 0; i < totDim; ++i) u_t[cind*totDim+i] = x_t[i]; 5382 PetscCall(DMPlexVecRestoreClosure(dm, section, X_t, cell, NULL, &x_t)); 5383 } 5384 if (dmAux) { 5385 PetscInt subcell; 5386 PetscCall(DMGetEnclosurePoint(dmAux, dm, encAux, cell, &subcell)); 5387 PetscCall(DMPlexVecGetClosure(plex, sectionAux, A, subcell, NULL, &x)); 5388 for (i = 0; i < totDimAux; ++i) a[cind*totDimAux+i] = x[i]; 5389 PetscCall(DMPlexVecRestoreClosure(plex, sectionAux, A, subcell, NULL, &x)); 5390 } 5391 } 5392 if (hasJac) PetscCall(PetscArrayzero(elemMat, numCells*totDim*totDim)); 5393 if (hasPrec) PetscCall(PetscArrayzero(elemMatP, numCells*totDim*totDim)); 5394 if (hasDyn) PetscCall(PetscArrayzero(elemMatD, numCells*totDim*totDim)); 5395 for (fieldI = 0; fieldI < Nf; ++fieldI) { 5396 PetscClassId id; 5397 PetscFE fe; 5398 PetscQuadrature qGeom = NULL; 5399 PetscInt Nb; 5400 /* Conforming batches */ 5401 PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize; 5402 /* Remainder */ 5403 PetscInt Nr, offset, Nq; 5404 PetscInt maxDegree; 5405 PetscFEGeom *cgeomFEM, *chunkGeom = NULL, *remGeom = NULL; 5406 5407 PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fe)); 5408 PetscCall(PetscObjectGetClassId((PetscObject) fe, &id)); 5409 if (id == PETSCFV_CLASSID) {hasFV = PETSC_TRUE; continue;} 5410 PetscCall(PetscFEGetDimension(fe, &Nb)); 5411 PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 5412 PetscCall(DMFieldGetDegree(coordField,cellIS,NULL,&maxDegree)); 5413 if (maxDegree <= 1) { 5414 PetscCall(DMFieldCreateDefaultQuadrature(coordField,cellIS,&qGeom)); 5415 } 5416 if (!qGeom) { 5417 PetscCall(PetscFEGetQuadrature(fe,&qGeom)); 5418 PetscCall(PetscObjectReference((PetscObject)qGeom)); 5419 } 5420 PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL)); 5421 PetscCall(DMSNESGetFEGeom(coordField,cellIS,qGeom,PETSC_FALSE,&cgeomFEM)); 5422 blockSize = Nb; 5423 batchSize = numBlocks * blockSize; 5424 PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 5425 numChunks = numCells / (numBatches*batchSize); 5426 Ne = numChunks*numBatches*batchSize; 5427 Nr = numCells % (numBatches*batchSize); 5428 offset = numCells - Nr; 5429 PetscCall(PetscFEGeomGetChunk(cgeomFEM,0,offset,&chunkGeom)); 5430 PetscCall(PetscFEGeomGetChunk(cgeomFEM,offset,numCells,&remGeom)); 5431 for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 5432 key.field = fieldI*Nf+fieldJ; 5433 if (hasJac) { 5434 PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat)); 5435 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])); 5436 } 5437 if (hasPrec) { 5438 PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatP)); 5439 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])); 5440 } 5441 if (hasDyn) { 5442 PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatD)); 5443 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])); 5444 } 5445 } 5446 PetscCall(PetscFEGeomRestoreChunk(cgeomFEM,offset,numCells,&remGeom)); 5447 PetscCall(PetscFEGeomRestoreChunk(cgeomFEM,0,offset,&chunkGeom)); 5448 PetscCall(DMSNESRestoreFEGeom(coordField,cellIS,qGeom,PETSC_FALSE,&cgeomFEM)); 5449 PetscCall(PetscQuadratureDestroy(&qGeom)); 5450 } 5451 /* Add contribution from X_t */ 5452 if (hasDyn) {for (c = 0; c < numCells*totDim*totDim; ++c) elemMat[c] += X_tShift*elemMatD[c];} 5453 if (hasFV) { 5454 PetscClassId id; 5455 PetscFV fv; 5456 PetscInt offsetI, NcI, NbI = 1, fc, f; 5457 5458 for (fieldI = 0; fieldI < Nf; ++fieldI) { 5459 PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fv)); 5460 PetscCall(PetscDSGetFieldOffset(prob, fieldI, &offsetI)); 5461 PetscCall(PetscObjectGetClassId((PetscObject) fv, &id)); 5462 if (id != PETSCFV_CLASSID) continue; 5463 /* Put in the identity */ 5464 PetscCall(PetscFVGetNumComponents(fv, &NcI)); 5465 for (c = cStart; c < cEnd; ++c) { 5466 const PetscInt cind = c - cStart; 5467 const PetscInt eOffset = cind*totDim*totDim; 5468 for (fc = 0; fc < NcI; ++fc) { 5469 for (f = 0; f < NbI; ++f) { 5470 const PetscInt i = offsetI + f*NcI+fc; 5471 if (hasPrec) { 5472 if (hasJac) {elemMat[eOffset+i*totDim+i] = 1.0;} 5473 elemMatP[eOffset+i*totDim+i] = 1.0; 5474 } else {elemMat[eOffset+i*totDim+i] = 1.0;} 5475 } 5476 } 5477 } 5478 } 5479 /* No allocated space for FV stuff, so ignore the zero entries */ 5480 PetscCall(MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE)); 5481 } 5482 /* Insert values into matrix */ 5483 for (c = cStart; c < cEnd; ++c) { 5484 const PetscInt cell = cells ? cells[c] : c; 5485 const PetscInt cind = c - cStart; 5486 5487 /* Transform to global basis before insertion in Jacobian */ 5488 if (transform) PetscCall(DMPlexBasisTransformPointTensor_Internal(dm, tdm, tv, cell, PETSC_TRUE, totDim, &elemMat[cind*totDim*totDim])); 5489 if (hasPrec) { 5490 if (hasJac) { 5491 if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind*totDim*totDim])); 5492 PetscCall(DMPlexMatSetClosure(dm, section, globalSection, Jac, cell, &elemMat[cind*totDim*totDim], ADD_VALUES)); 5493 } 5494 if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatP[cind*totDim*totDim])); 5495 PetscCall(DMPlexMatSetClosure(dm, section, globalSection, JacP, cell, &elemMatP[cind*totDim*totDim], ADD_VALUES)); 5496 } else { 5497 if (hasJac) { 5498 if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind*totDim*totDim])); 5499 PetscCall(DMPlexMatSetClosure(dm, section, globalSection, JacP, cell, &elemMat[cind*totDim*totDim], ADD_VALUES)); 5500 } 5501 } 5502 } 5503 PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 5504 if (hasFV) PetscCall(MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_FALSE)); 5505 PetscCall(PetscFree5(u,u_t,elemMat,elemMatP,elemMatD)); 5506 if (dmAux) { 5507 PetscCall(PetscFree(a)); 5508 PetscCall(DMDestroy(&plex)); 5509 } 5510 /* Compute boundary integrals */ 5511 PetscCall(DMPlexComputeBdJacobian_Internal(dm, X, X_t, t, X_tShift, Jac, JacP, user)); 5512 /* Assemble matrix */ 5513 if (hasJac && hasPrec) { 5514 PetscCall(MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY)); 5515 PetscCall(MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY)); 5516 } 5517 PetscCall(MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY)); 5518 PetscCall(MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY)); 5519 PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM,dm,0,0,0)); 5520 PetscFunctionReturn(0); 5521 } 5522 5523 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) 5524 { 5525 DM_Plex *mesh = (DM_Plex *) dm->data; 5526 const char *name = "Hybrid Jacobian"; 5527 DM dmAux[3] = {NULL, NULL, NULL}; 5528 DMLabel ghostLabel = NULL; 5529 DM plex = NULL; 5530 DM plexA = NULL; 5531 PetscDS ds = NULL; 5532 PetscDS dsAux[3] = {NULL, NULL, NULL}; 5533 Vec locA[3] = {NULL, NULL, NULL}; 5534 PetscSection section = NULL; 5535 PetscSection sectionAux[3] = {NULL, NULL, NULL}; 5536 DMField coordField = NULL; 5537 PetscScalar *u = NULL, *u_t, *a[3]; 5538 PetscScalar *elemMat, *elemMatP; 5539 PetscSection globalSection; 5540 IS chunkIS; 5541 const PetscInt *cells; 5542 PetscInt *faces; 5543 PetscInt cStart, cEnd, numCells; 5544 PetscInt Nf, fieldI, fieldJ, totDim, totDimAux[3], numChunks, cellChunkSize, chunk; 5545 PetscInt maxDegree = PETSC_MAX_INT; 5546 PetscQuadrature affineQuad = NULL, *quads = NULL; 5547 PetscFEGeom *affineGeom = NULL, **geoms = NULL; 5548 PetscBool hasBdJac, hasBdPrec; 5549 5550 PetscFunctionBegin; 5551 if ((key[0].label == key[1].label) && (key[0].value == key[1].value) && (key[0].part == key[1].part)) { 5552 const char *name; 5553 PetscCall(PetscObjectGetName((PetscObject) key[0].label, &name)); 5554 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Form keys for each side of a cohesive surface must be different (%s, %D, %D)", name, key[0].value, key[0].part); 5555 } 5556 PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM,dm,0,0,0)); 5557 PetscCall(ISGetLocalSize(cellIS, &numCells)); 5558 PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 5559 PetscCall(DMConvert(dm, DMPLEX, &plex)); 5560 PetscCall(DMGetSection(dm, §ion)); 5561 PetscCall(DMGetGlobalSection(dm, &globalSection)); 5562 PetscCall(DMGetLabel(dm, "ghost", &ghostLabel)); 5563 PetscCall(DMGetCellDS(dm, cStart, &ds)); 5564 PetscCall(PetscDSGetNumFields(ds, &Nf)); 5565 PetscCall(PetscDSGetTotalDimension(ds, &totDim)); 5566 PetscCall(PetscDSHasBdJacobian(ds, &hasBdJac)); 5567 PetscCall(PetscDSHasBdJacobianPreconditioner(ds, &hasBdPrec)); 5568 PetscCall(DMGetAuxiliaryVec(dm, key[2].label, key[2].value, key[2].part, &locA[2])); 5569 if (locA[2]) { 5570 PetscCall(VecGetDM(locA[2], &dmAux[2])); 5571 PetscCall(DMConvert(dmAux[2], DMPLEX, &plexA)); 5572 PetscCall(DMGetSection(dmAux[2], §ionAux[2])); 5573 PetscCall(DMGetCellDS(dmAux[2], cStart, &dsAux[2])); 5574 PetscCall(PetscDSGetTotalDimension(dsAux[2], &totDimAux[2])); 5575 { 5576 const PetscInt *cone; 5577 PetscInt c; 5578 5579 PetscCall(DMPlexGetCone(dm, cStart, &cone)); 5580 for (c = 0; c < 2; ++c) { 5581 const PetscInt *support; 5582 PetscInt ssize, s; 5583 5584 PetscCall(DMPlexGetSupport(dm, cone[c], &support)); 5585 PetscCall(DMPlexGetSupportSize(dm, cone[c], &ssize)); 5586 PetscCheck(ssize == 2,PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %D from cell %D has support size %D != 2", cone[c], cStart, ssize); 5587 if (support[0] == cStart) s = 1; 5588 else if (support[1] == cStart) s = 0; 5589 else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Face %D does not have cell %D in its support", cone[c], cStart); 5590 PetscCall(DMGetAuxiliaryVec(dm, key[c].label, key[c].value, key[c].part, &locA[c])); 5591 if (locA[c]) PetscCall(VecGetDM(locA[c], &dmAux[c])); 5592 else {dmAux[c] = dmAux[2];} 5593 PetscCall(DMGetCellDS(dmAux[c], support[s], &dsAux[c])); 5594 PetscCall(PetscDSGetTotalDimension(dsAux[c], &totDimAux[c])); 5595 } 5596 } 5597 } 5598 PetscCall(DMGetCoordinateField(dm, &coordField)); 5599 PetscCall(DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree)); 5600 if (maxDegree > 1) { 5601 PetscInt f; 5602 PetscCall(PetscCalloc2(Nf, &quads, Nf, &geoms)); 5603 for (f = 0; f < Nf; ++f) { 5604 PetscFE fe; 5605 5606 PetscCall(PetscDSGetDiscretization(ds, f, (PetscObject *) &fe)); 5607 if (fe) { 5608 PetscCall(PetscFEGetQuadrature(fe, &quads[f])); 5609 PetscCall(PetscObjectReference((PetscObject) quads[f])); 5610 } 5611 } 5612 } 5613 cellChunkSize = numCells; 5614 numChunks = !numCells ? 0 : PetscCeilReal(((PetscReal) numCells)/cellChunkSize); 5615 PetscCall(PetscCalloc1(2*cellChunkSize, &faces)); 5616 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, cellChunkSize, faces, PETSC_USE_POINTER, &chunkIS)); 5617 PetscCall(DMPlexGetCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2])); 5618 PetscCall(DMPlexGetHybridAuxFields(dm, dmAux, dsAux, cellIS, locA, a)); 5619 PetscCall(DMGetWorkArray(dm, hasBdJac ? cellChunkSize*totDim*totDim : 0, MPIU_SCALAR, &elemMat)); 5620 PetscCall(DMGetWorkArray(dm, hasBdPrec ? cellChunkSize*totDim*totDim : 0, MPIU_SCALAR, &elemMatP)); 5621 for (chunk = 0; chunk < numChunks; ++chunk) { 5622 PetscInt cS = cStart+chunk*cellChunkSize, cE = PetscMin(cS+cellChunkSize, cEnd), numCells = cE - cS, c; 5623 5624 if (hasBdJac) PetscCall(PetscMemzero(elemMat, numCells*totDim*totDim * sizeof(PetscScalar))); 5625 if (hasBdPrec) PetscCall(PetscMemzero(elemMatP, numCells*totDim*totDim * sizeof(PetscScalar))); 5626 /* Get faces */ 5627 for (c = cS; c < cE; ++c) { 5628 const PetscInt cell = cells ? cells[c] : c; 5629 const PetscInt *cone; 5630 PetscCall(DMPlexGetCone(plex, cell, &cone)); 5631 faces[(c-cS)*2+0] = cone[0]; 5632 faces[(c-cS)*2+1] = cone[1]; 5633 } 5634 PetscCall(ISGeneralSetIndices(chunkIS, cellChunkSize, faces, PETSC_USE_POINTER)); 5635 if (maxDegree <= 1) { 5636 if (!affineQuad) PetscCall(DMFieldCreateDefaultQuadrature(coordField, chunkIS, &affineQuad)); 5637 if (affineQuad) PetscCall(DMSNESGetFEGeom(coordField, chunkIS, affineQuad, PETSC_TRUE, &affineGeom)); 5638 } else { 5639 PetscInt f; 5640 for (f = 0; f < Nf; ++f) { 5641 if (quads[f]) PetscCall(DMSNESGetFEGeom(coordField, chunkIS, quads[f], PETSC_TRUE, &geoms[f])); 5642 } 5643 } 5644 5645 for (fieldI = 0; fieldI < Nf; ++fieldI) { 5646 PetscFE feI; 5647 PetscFEGeom *geom = affineGeom ? affineGeom : geoms[fieldI]; 5648 PetscFEGeom *chunkGeom = NULL, *remGeom = NULL; 5649 PetscQuadrature quad = affineQuad ? affineQuad : quads[fieldI]; 5650 PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset, Nq, Nb; 5651 PetscBool isCohesiveField; 5652 5653 PetscCall(PetscDSGetDiscretization(ds, fieldI, (PetscObject *) &feI)); 5654 if (!feI) continue; 5655 PetscCall(PetscFEGetTileSizes(feI, NULL, &numBlocks, NULL, &numBatches)); 5656 PetscCall(PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL)); 5657 PetscCall(PetscFEGetDimension(feI, &Nb)); 5658 blockSize = Nb; 5659 batchSize = numBlocks * blockSize; 5660 PetscCall(PetscFESetTileSizes(feI, blockSize, numBlocks, batchSize, numBatches)); 5661 numChunks = numCells / (numBatches*batchSize); 5662 Ne = numChunks*numBatches*batchSize; 5663 Nr = numCells % (numBatches*batchSize); 5664 offset = numCells - Nr; 5665 PetscCall(PetscFEGeomGetChunk(geom,0,offset,&chunkGeom)); 5666 PetscCall(PetscFEGeomGetChunk(geom,offset,numCells,&remGeom)); 5667 PetscCall(PetscDSGetCohesive(ds, fieldI, &isCohesiveField)); 5668 for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 5669 PetscFE feJ; 5670 5671 PetscCall(PetscDSGetDiscretization(ds, fieldJ, (PetscObject *) &feJ)); 5672 if (!feJ) continue; 5673 key[0].field = fieldI*Nf+fieldJ; 5674 key[1].field = fieldI*Nf+fieldJ; 5675 key[2].field = fieldI*Nf+fieldJ; 5676 if (hasBdJac) { 5677 PetscCall(PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN, key[0], 0, Ne, chunkGeom, u, u_t, dsAux[0], a[0], t, X_tShift, elemMat)); 5678 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])); 5679 PetscCall(PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN, key[1], 1, Ne, chunkGeom, u, u_t, dsAux[1], a[1], t, X_tShift, elemMat)); 5680 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])); 5681 } 5682 if (hasBdPrec) { 5683 PetscCall(PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN_PRE, key[0], 0, Ne, chunkGeom, u, u_t, dsAux[0], a[0], t, X_tShift, elemMatP)); 5684 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])); 5685 PetscCall(PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN_PRE, key[1], 1, Ne, chunkGeom, u, u_t, dsAux[1], a[1], t, X_tShift, elemMatP)); 5686 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])); 5687 } 5688 if (hasBdJac) { 5689 PetscCall(PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN, key[2], 2, Ne, chunkGeom, u, u_t, dsAux[2], a[2], t, X_tShift, elemMat)); 5690 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])); 5691 } 5692 if (hasBdPrec) { 5693 PetscCall(PetscFEIntegrateHybridJacobian(ds, PETSCFE_JACOBIAN_PRE, key[2], 2, Ne, chunkGeom, u, u_t, dsAux[2], a[2], t, X_tShift, elemMatP)); 5694 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])); 5695 } 5696 } 5697 PetscCall(PetscFEGeomRestoreChunk(geom,offset,numCells,&remGeom)); 5698 PetscCall(PetscFEGeomRestoreChunk(geom,0,offset,&chunkGeom)); 5699 } 5700 /* Insert values into matrix */ 5701 for (c = cS; c < cE; ++c) { 5702 const PetscInt cell = cells ? cells[c] : c; 5703 const PetscInt cind = c - cS; 5704 5705 if (hasBdPrec) { 5706 if (hasBdJac) { 5707 if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind*totDim*totDim])); 5708 PetscCall(DMPlexMatSetClosure(plex, section, globalSection, Jac, cell, &elemMat[cind*totDim*totDim], ADD_VALUES)); 5709 } 5710 if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatP[cind*totDim*totDim])); 5711 PetscCall(DMPlexMatSetClosure(plex, section, globalSection, JacP, cell, &elemMatP[cind*totDim*totDim], ADD_VALUES)); 5712 } else if (hasBdJac) { 5713 if (mesh->printFEM > 1) PetscCall(DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind*totDim*totDim])); 5714 PetscCall(DMPlexMatSetClosure(plex, section, globalSection, JacP, cell, &elemMat[cind*totDim*totDim], ADD_VALUES)); 5715 } 5716 } 5717 } 5718 PetscCall(DMPlexRestoreCellFields(dm, cellIS, locX, locX_t, locA[2], &u, &u_t, &a[2])); 5719 PetscCall(DMPlexRestoreHybridAuxFields(dmAux, dsAux, cellIS, locA, a)); 5720 PetscCall(DMRestoreWorkArray(dm, hasBdJac ? cellChunkSize*totDim*totDim : 0, MPIU_SCALAR, &elemMat)); 5721 PetscCall(DMRestoreWorkArray(dm, hasBdPrec ? cellChunkSize*totDim*totDim : 0, MPIU_SCALAR, &elemMatP)); 5722 PetscCall(PetscFree(faces)); 5723 PetscCall(ISDestroy(&chunkIS)); 5724 PetscCall(ISRestorePointRange(cellIS, &cStart, &cEnd, &cells)); 5725 if (maxDegree <= 1) { 5726 PetscCall(DMSNESRestoreFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom)); 5727 PetscCall(PetscQuadratureDestroy(&affineQuad)); 5728 } else { 5729 PetscInt f; 5730 for (f = 0; f < Nf; ++f) { 5731 if (geoms) PetscCall(DMSNESRestoreFEGeom(coordField,cellIS,quads[f],PETSC_FALSE, &geoms[f])); 5732 if (quads) PetscCall(PetscQuadratureDestroy(&quads[f])); 5733 } 5734 PetscCall(PetscFree2(quads,geoms)); 5735 } 5736 if (dmAux[2]) PetscCall(DMDestroy(&plexA)); 5737 PetscCall(DMDestroy(&plex)); 5738 /* Assemble matrix */ 5739 if (hasBdJac && hasBdPrec) { 5740 PetscCall(MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY)); 5741 PetscCall(MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY)); 5742 } 5743 PetscCall(MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY)); 5744 PetscCall(MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY)); 5745 PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM,dm,0,0,0)); 5746 PetscFunctionReturn(0); 5747 } 5748 5749 /* 5750 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. 5751 5752 Input Parameters: 5753 + dm - The mesh 5754 . key - The PetscWeakFormKey indcating where integration should happen 5755 . cellIS - The cells to integrate over 5756 . t - The time 5757 . X_tShift - The multiplier for the Jacobian with repsect to X_t 5758 . X - Local solution vector 5759 . X_t - Time-derivative of the local solution vector 5760 . Y - Local input vector 5761 - user - the user context 5762 5763 Output Parameter: 5764 . Z - Local output vector 5765 5766 Note: 5767 We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator, 5768 like a GPU, or vectorize on a multicore machine. 5769 */ 5770 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) 5771 { 5772 DM_Plex *mesh = (DM_Plex *) dm->data; 5773 const char *name = "Jacobian"; 5774 DM dmAux = NULL, plex, plexAux = NULL; 5775 DMEnclosureType encAux; 5776 Vec A; 5777 DMField coordField; 5778 PetscDS prob, probAux = NULL; 5779 PetscQuadrature quad; 5780 PetscSection section, globalSection, sectionAux; 5781 PetscScalar *elemMat, *elemMatD, *u, *u_t, *a = NULL, *y, *z; 5782 const PetscInt *cells; 5783 PetscInt Nf, fieldI, fieldJ; 5784 PetscInt totDim, totDimAux = 0, cStart, cEnd, numCells, c; 5785 PetscBool hasDyn; 5786 5787 PetscFunctionBegin; 5788 PetscCall(PetscLogEventBegin(DMPLEX_JacobianFEM,dm,0,0,0)); 5789 PetscCall(DMConvert(dm, DMPLEX, &plex)); 5790 if (!cellIS) { 5791 PetscInt depth; 5792 5793 PetscCall(DMPlexGetDepth(plex, &depth)); 5794 PetscCall(DMGetStratumIS(plex, "dim", depth, &cellIS)); 5795 if (!cellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, &cellIS)); 5796 } else { 5797 PetscCall(PetscObjectReference((PetscObject) cellIS)); 5798 } 5799 PetscCall(ISGetLocalSize(cellIS, &numCells)); 5800 PetscCall(ISGetPointRange(cellIS, &cStart, &cEnd, &cells)); 5801 PetscCall(DMGetLocalSection(dm, §ion)); 5802 PetscCall(DMGetGlobalSection(dm, &globalSection)); 5803 PetscCall(DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob)); 5804 PetscCall(PetscDSGetNumFields(prob, &Nf)); 5805 PetscCall(PetscDSGetTotalDimension(prob, &totDim)); 5806 PetscCall(PetscDSHasDynamicJacobian(prob, &hasDyn)); 5807 hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE; 5808 PetscCall(DMGetAuxiliaryVec(dm, key.label, key.value, key.part, &A)); 5809 if (A) { 5810 PetscCall(VecGetDM(A, &dmAux)); 5811 PetscCall(DMGetEnclosureRelation(dmAux, dm, &encAux)); 5812 PetscCall(DMConvert(dmAux, DMPLEX, &plexAux)); 5813 PetscCall(DMGetLocalSection(plexAux, §ionAux)); 5814 PetscCall(DMGetDS(dmAux, &probAux)); 5815 PetscCall(PetscDSGetTotalDimension(probAux, &totDimAux)); 5816 } 5817 PetscCall(VecSet(Z, 0.0)); 5818 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)); 5819 if (dmAux) PetscCall(PetscMalloc1(numCells*totDimAux, &a)); 5820 PetscCall(DMGetCoordinateField(dm, &coordField)); 5821 for (c = cStart; c < cEnd; ++c) { 5822 const PetscInt cell = cells ? cells[c] : c; 5823 const PetscInt cind = c - cStart; 5824 PetscScalar *x = NULL, *x_t = NULL; 5825 PetscInt i; 5826 5827 PetscCall(DMPlexVecGetClosure(plex, section, X, cell, NULL, &x)); 5828 for (i = 0; i < totDim; ++i) u[cind*totDim+i] = x[i]; 5829 PetscCall(DMPlexVecRestoreClosure(plex, section, X, cell, NULL, &x)); 5830 if (X_t) { 5831 PetscCall(DMPlexVecGetClosure(plex, section, X_t, cell, NULL, &x_t)); 5832 for (i = 0; i < totDim; ++i) u_t[cind*totDim+i] = x_t[i]; 5833 PetscCall(DMPlexVecRestoreClosure(plex, section, X_t, cell, NULL, &x_t)); 5834 } 5835 if (dmAux) { 5836 PetscInt subcell; 5837 PetscCall(DMGetEnclosurePoint(dmAux, dm, encAux, cell, &subcell)); 5838 PetscCall(DMPlexVecGetClosure(plexAux, sectionAux, A, subcell, NULL, &x)); 5839 for (i = 0; i < totDimAux; ++i) a[cind*totDimAux+i] = x[i]; 5840 PetscCall(DMPlexVecRestoreClosure(plexAux, sectionAux, A, subcell, NULL, &x)); 5841 } 5842 PetscCall(DMPlexVecGetClosure(plex, section, Y, cell, NULL, &x)); 5843 for (i = 0; i < totDim; ++i) y[cind*totDim+i] = x[i]; 5844 PetscCall(DMPlexVecRestoreClosure(plex, section, Y, cell, NULL, &x)); 5845 } 5846 PetscCall(PetscArrayzero(elemMat, numCells*totDim*totDim)); 5847 if (hasDyn) PetscCall(PetscArrayzero(elemMatD, numCells*totDim*totDim)); 5848 for (fieldI = 0; fieldI < Nf; ++fieldI) { 5849 PetscFE fe; 5850 PetscInt Nb; 5851 /* Conforming batches */ 5852 PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize; 5853 /* Remainder */ 5854 PetscInt Nr, offset, Nq; 5855 PetscQuadrature qGeom = NULL; 5856 PetscInt maxDegree; 5857 PetscFEGeom *cgeomFEM, *chunkGeom = NULL, *remGeom = NULL; 5858 5859 PetscCall(PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fe)); 5860 PetscCall(PetscFEGetQuadrature(fe, &quad)); 5861 PetscCall(PetscFEGetDimension(fe, &Nb)); 5862 PetscCall(PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches)); 5863 PetscCall(DMFieldGetDegree(coordField,cellIS,NULL,&maxDegree)); 5864 if (maxDegree <= 1) PetscCall(DMFieldCreateDefaultQuadrature(coordField,cellIS,&qGeom)); 5865 if (!qGeom) { 5866 PetscCall(PetscFEGetQuadrature(fe,&qGeom)); 5867 PetscCall(PetscObjectReference((PetscObject)qGeom)); 5868 } 5869 PetscCall(PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL)); 5870 PetscCall(DMSNESGetFEGeom(coordField,cellIS,qGeom,PETSC_FALSE,&cgeomFEM)); 5871 blockSize = Nb; 5872 batchSize = numBlocks * blockSize; 5873 PetscCall(PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches)); 5874 numChunks = numCells / (numBatches*batchSize); 5875 Ne = numChunks*numBatches*batchSize; 5876 Nr = numCells % (numBatches*batchSize); 5877 offset = numCells - Nr; 5878 PetscCall(PetscFEGeomGetChunk(cgeomFEM,0,offset,&chunkGeom)); 5879 PetscCall(PetscFEGeomGetChunk(cgeomFEM,offset,numCells,&remGeom)); 5880 for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 5881 key.field = fieldI*Nf + fieldJ; 5882 PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat)); 5883 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])); 5884 if (hasDyn) { 5885 PetscCall(PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, key, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatD)); 5886 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])); 5887 } 5888 } 5889 PetscCall(PetscFEGeomRestoreChunk(cgeomFEM,offset,numCells,&remGeom)); 5890 PetscCall(PetscFEGeomRestoreChunk(cgeomFEM,0,offset,&chunkGeom)); 5891 PetscCall(DMSNESRestoreFEGeom(coordField,cellIS,qGeom,PETSC_FALSE,&cgeomFEM)); 5892 PetscCall(PetscQuadratureDestroy(&qGeom)); 5893 } 5894 if (hasDyn) { 5895 for (c = 0; c < numCells*totDim*totDim; ++c) elemMat[c] += X_tShift*elemMatD[c]; 5896 } 5897 for (c = cStart; c < cEnd; ++c) { 5898 const PetscInt cell = cells ? cells[c] : c; 5899 const PetscInt cind = c - cStart; 5900 const PetscBLASInt M = totDim, one = 1; 5901 const PetscScalar a = 1.0, b = 0.0; 5902 5903 PetscStackCallBLAS("BLASgemv", BLASgemv_("N", &M, &M, &a, &elemMat[cind*totDim*totDim], &M, &y[cind*totDim], &one, &b, z, &one)); 5904 if (mesh->printFEM > 1) { 5905 PetscCall(DMPrintCellMatrix(c, name, totDim, totDim, &elemMat[cind*totDim*totDim])); 5906 PetscCall(DMPrintCellVector(c, "Y", totDim, &y[cind*totDim])); 5907 PetscCall(DMPrintCellVector(c, "Z", totDim, z)); 5908 } 5909 PetscCall(DMPlexVecSetClosure(dm, section, Z, cell, z, ADD_VALUES)); 5910 } 5911 PetscCall(PetscFree6(u,u_t,elemMat,elemMatD,y,z)); 5912 if (mesh->printFEM) { 5913 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)Z), "Z:\n")); 5914 PetscCall(VecView(Z, NULL)); 5915 } 5916 PetscCall(PetscFree(a)); 5917 PetscCall(ISDestroy(&cellIS)); 5918 PetscCall(DMDestroy(&plexAux)); 5919 PetscCall(DMDestroy(&plex)); 5920 PetscCall(PetscLogEventEnd(DMPLEX_JacobianFEM,dm,0,0,0)); 5921 PetscFunctionReturn(0); 5922 } 5923