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