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