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);break; 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);break; 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, &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, &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, *cone; 2244 PetscScalar *x = NULL; 2245 PetscInt i, coneSize, faceLoc; 2246 2247 ierr = DMPlexGetSupport(dm, point, &support);CHKERRQ(ierr); 2248 ierr = DMPlexGetConeSize(dm, support[0], &coneSize);CHKERRQ(ierr); 2249 ierr = DMPlexGetCone(dm, support[0], &cone);CHKERRQ(ierr); 2250 for (faceLoc = 0; faceLoc < coneSize; ++faceLoc) if (cone[faceLoc] == point) break; 2251 if (faceLoc == coneSize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %D in cone of support[0] %D", face, support[0]); 2252 fgeom->face[face][0] = faceLoc; 2253 ierr = DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x);CHKERRQ(ierr); 2254 for (i = 0; i < totDim; ++i) u[face*totDim+i] = x[i]; 2255 ierr = DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x);CHKERRQ(ierr); 2256 if (locA) { 2257 PetscInt subp; 2258 ierr = DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp);CHKERRQ(ierr); 2259 ierr = DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x);CHKERRQ(ierr); 2260 for (i = 0; i < totDimAux; ++i) a[f*totDimAux+i] = x[i]; 2261 ierr = DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x);CHKERRQ(ierr); 2262 } 2263 } 2264 /* Get blocking */ 2265 { 2266 PetscQuadrature q; 2267 PetscInt numBatches, batchSize, numBlocks, blockSize; 2268 PetscInt Nq, Nb; 2269 2270 ierr = PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);CHKERRQ(ierr); 2271 ierr = PetscFEGetQuadrature(fe, &q);CHKERRQ(ierr); 2272 ierr = PetscQuadratureGetData(q, NULL, NULL, &Nq, NULL, NULL);CHKERRQ(ierr); 2273 ierr = PetscFEGetDimension(fe, &Nb);CHKERRQ(ierr); 2274 blockSize = Nb*Nq; 2275 batchSize = numBlocks * blockSize; 2276 chunkSize = numBatches*batchSize; 2277 ierr = PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);CHKERRQ(ierr); 2278 numChunks = numFaces / chunkSize; 2279 Nr = numFaces % chunkSize; 2280 offset = numFaces - Nr; 2281 } 2282 /* Do integration for each field */ 2283 for (chunk = 0; chunk < numChunks; ++chunk) { 2284 ierr = PetscFEGeomGetChunk(fgeom, chunk*chunkSize, (chunk+1)*chunkSize, &chunkGeom);CHKERRQ(ierr); 2285 ierr = PetscFEIntegrateBd(prob, field, func, chunkSize, chunkGeom, u, probAux, a, fintegral);CHKERRQ(ierr); 2286 ierr = PetscFEGeomRestoreChunk(fgeom, 0, offset, &chunkGeom);CHKERRQ(ierr); 2287 } 2288 ierr = PetscFEGeomGetChunk(fgeom, offset, numFaces, &chunkGeom);CHKERRQ(ierr); 2289 ierr = PetscFEIntegrateBd(prob, field, func, Nr, chunkGeom, &u[offset*totDim], probAux, a ? &a[offset*totDimAux] : NULL, &fintegral[offset*Nf]);CHKERRQ(ierr); 2290 ierr = PetscFEGeomRestoreChunk(fgeom, offset, numFaces, &chunkGeom);CHKERRQ(ierr); 2291 /* Cleanup data arrays */ 2292 ierr = DMPlexRestoreFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom);CHKERRQ(ierr); 2293 ierr = PetscQuadratureDestroy(&qGeom);CHKERRQ(ierr); 2294 ierr = PetscFree2(u, a);CHKERRQ(ierr); 2295 ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr); 2296 } 2297 } 2298 if (plex) {ierr = DMDestroy(&plex);CHKERRQ(ierr);} 2299 if (plexA) {ierr = DMDestroy(&plexA);CHKERRQ(ierr);} 2300 PetscFunctionReturn(0); 2301 } 2302 2303 /*@ 2304 DMPlexComputeBdIntegral - Form the integral over the specified boundary from the global input X using pointwise functions specified by the user 2305 2306 Input Parameters: 2307 + dm - The mesh 2308 . X - Global input vector 2309 . label - The boundary DMLabel 2310 . numVals - The number of label values to use, or PETSC_DETERMINE for all values 2311 . vals - The label values to use, or PETSC_NULL for all values 2312 . func = The function to integrate along the boundary 2313 - user - The user context 2314 2315 Output Parameter: 2316 . integral - Integral for each field 2317 2318 Level: developer 2319 2320 .seealso: DMPlexComputeIntegralFEM(), DMPlexComputeBdResidualFEM() 2321 @*/ 2322 PetscErrorCode DMPlexComputeBdIntegral(DM dm, Vec X, DMLabel label, PetscInt numVals, const PetscInt vals[], 2323 void (*func)(PetscInt, PetscInt, PetscInt, 2324 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 2325 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 2326 PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), 2327 PetscScalar *integral, void *user) 2328 { 2329 Vec locX; 2330 PetscSection section; 2331 DMLabel depthLabel; 2332 IS facetIS; 2333 PetscInt dim, Nf, f, v; 2334 PetscErrorCode ierr; 2335 2336 PetscFunctionBegin; 2337 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2338 PetscValidHeaderSpecific(X, VEC_CLASSID, 2); 2339 PetscValidPointer(label, 3); 2340 if (vals) PetscValidPointer(vals, 5); 2341 PetscValidPointer(integral, 6); 2342 ierr = PetscLogEventBegin(DMPLEX_IntegralFEM,dm,0,0,0);CHKERRQ(ierr); 2343 ierr = DMPlexGetDepthLabel(dm, &depthLabel);CHKERRQ(ierr); 2344 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 2345 ierr = DMLabelGetStratumIS(depthLabel, dim-1, &facetIS);CHKERRQ(ierr); 2346 ierr = DMGetLocalSection(dm, §ion);CHKERRQ(ierr); 2347 ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr); 2348 /* Get local solution with boundary values */ 2349 ierr = DMGetLocalVector(dm, &locX);CHKERRQ(ierr); 2350 ierr = DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locX, 0.0, NULL, NULL, NULL);CHKERRQ(ierr); 2351 ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, locX);CHKERRQ(ierr); 2352 ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, locX);CHKERRQ(ierr); 2353 /* Loop over label values */ 2354 ierr = PetscArrayzero(integral, Nf);CHKERRQ(ierr); 2355 for (v = 0; v < numVals; ++v) { 2356 IS pointIS; 2357 PetscInt numFaces, face; 2358 PetscScalar *fintegral; 2359 2360 ierr = DMLabelGetStratumIS(label, vals[v], &pointIS);CHKERRQ(ierr); 2361 if (!pointIS) continue; /* No points with that id on this process */ 2362 { 2363 IS isectIS; 2364 2365 /* TODO: Special cases of ISIntersect where it is quick to check a priori if one is a superset of the other */ 2366 ierr = ISIntersect_Caching_Internal(facetIS, pointIS, &isectIS);CHKERRQ(ierr); 2367 ierr = ISDestroy(&pointIS);CHKERRQ(ierr); 2368 pointIS = isectIS; 2369 } 2370 ierr = ISGetLocalSize(pointIS, &numFaces);CHKERRQ(ierr); 2371 ierr = PetscCalloc1(numFaces*Nf, &fintegral);CHKERRQ(ierr); 2372 ierr = DMPlexComputeBdIntegral_Internal(dm, locX, pointIS, func, fintegral, user);CHKERRQ(ierr); 2373 /* Sum point contributions into integral */ 2374 for (f = 0; f < Nf; ++f) for (face = 0; face < numFaces; ++face) integral[f] += fintegral[face*Nf+f]; 2375 ierr = PetscFree(fintegral);CHKERRQ(ierr); 2376 ierr = ISDestroy(&pointIS);CHKERRQ(ierr); 2377 } 2378 ierr = DMRestoreLocalVector(dm, &locX);CHKERRQ(ierr); 2379 ierr = ISDestroy(&facetIS);CHKERRQ(ierr); 2380 ierr = PetscLogEventEnd(DMPLEX_IntegralFEM,dm,0,0,0);CHKERRQ(ierr); 2381 PetscFunctionReturn(0); 2382 } 2383 2384 /*@ 2385 DMPlexComputeInterpolatorNested - Form the local portion of the interpolation matrix I from the coarse DM to a uniformly refined DM. 2386 2387 Input Parameters: 2388 + dmc - The coarse mesh 2389 . dmf - The fine mesh 2390 . isRefined - Flag indicating regular refinement, rather than the same topology 2391 - user - The user context 2392 2393 Output Parameter: 2394 . In - The interpolation matrix 2395 2396 Level: developer 2397 2398 .seealso: DMPlexComputeInterpolatorGeneral(), DMPlexComputeJacobianFEM() 2399 @*/ 2400 PetscErrorCode DMPlexComputeInterpolatorNested(DM dmc, DM dmf, PetscBool isRefined, Mat In, void *user) 2401 { 2402 DM_Plex *mesh = (DM_Plex *) dmc->data; 2403 const char *name = "Interpolator"; 2404 PetscDS cds, rds; 2405 PetscFE *feRef; 2406 PetscFV *fvRef; 2407 PetscSection fsection, fglobalSection; 2408 PetscSection csection, cglobalSection; 2409 PetscScalar *elemMat; 2410 PetscInt dim, Nf, f, fieldI, fieldJ, offsetI, offsetJ, cStart, cEnd, c; 2411 PetscInt cTotDim, rTotDim = 0; 2412 PetscErrorCode ierr; 2413 2414 PetscFunctionBegin; 2415 ierr = PetscLogEventBegin(DMPLEX_InterpolatorFEM,dmc,dmf,0,0);CHKERRQ(ierr); 2416 ierr = DMGetDimension(dmf, &dim);CHKERRQ(ierr); 2417 ierr = DMGetLocalSection(dmf, &fsection);CHKERRQ(ierr); 2418 ierr = DMGetGlobalSection(dmf, &fglobalSection);CHKERRQ(ierr); 2419 ierr = DMGetLocalSection(dmc, &csection);CHKERRQ(ierr); 2420 ierr = DMGetGlobalSection(dmc, &cglobalSection);CHKERRQ(ierr); 2421 ierr = PetscSectionGetNumFields(fsection, &Nf);CHKERRQ(ierr); 2422 ierr = DMPlexGetSimplexOrBoxCells(dmc, 0, &cStart, &cEnd);CHKERRQ(ierr); 2423 ierr = DMGetDS(dmc, &cds);CHKERRQ(ierr); 2424 ierr = DMGetDS(dmf, &rds);CHKERRQ(ierr); 2425 ierr = PetscCalloc2(Nf, &feRef, Nf, &fvRef);CHKERRQ(ierr); 2426 for (f = 0; f < Nf; ++f) { 2427 PetscObject obj; 2428 PetscClassId id; 2429 PetscInt rNb = 0, Nc = 0; 2430 2431 ierr = PetscDSGetDiscretization(rds, f, &obj);CHKERRQ(ierr); 2432 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 2433 if (id == PETSCFE_CLASSID) { 2434 PetscFE fe = (PetscFE) obj; 2435 2436 if (isRefined) { 2437 ierr = PetscFERefine(fe, &feRef[f]);CHKERRQ(ierr); 2438 } else { 2439 ierr = PetscObjectReference((PetscObject) fe);CHKERRQ(ierr); 2440 feRef[f] = fe; 2441 } 2442 ierr = PetscFEGetDimension(feRef[f], &rNb);CHKERRQ(ierr); 2443 ierr = PetscFEGetNumComponents(fe, &Nc);CHKERRQ(ierr); 2444 } else if (id == PETSCFV_CLASSID) { 2445 PetscFV fv = (PetscFV) obj; 2446 PetscDualSpace Q; 2447 2448 if (isRefined) { 2449 ierr = PetscFVRefine(fv, &fvRef[f]);CHKERRQ(ierr); 2450 } else { 2451 ierr = PetscObjectReference((PetscObject) fv);CHKERRQ(ierr); 2452 fvRef[f] = fv; 2453 } 2454 ierr = PetscFVGetDualSpace(fvRef[f], &Q);CHKERRQ(ierr); 2455 ierr = PetscDualSpaceGetDimension(Q, &rNb);CHKERRQ(ierr); 2456 ierr = PetscFVGetNumComponents(fv, &Nc);CHKERRQ(ierr); 2457 } 2458 rTotDim += rNb; 2459 } 2460 ierr = PetscDSGetTotalDimension(cds, &cTotDim);CHKERRQ(ierr); 2461 ierr = PetscMalloc1(rTotDim*cTotDim,&elemMat);CHKERRQ(ierr); 2462 ierr = PetscArrayzero(elemMat, rTotDim*cTotDim);CHKERRQ(ierr); 2463 for (fieldI = 0, offsetI = 0; fieldI < Nf; ++fieldI) { 2464 PetscDualSpace Qref; 2465 PetscQuadrature f; 2466 const PetscReal *qpoints, *qweights; 2467 PetscReal *points; 2468 PetscInt npoints = 0, Nc, Np, fpdim, i, k, p, d; 2469 2470 /* Compose points from all dual basis functionals */ 2471 if (feRef[fieldI]) { 2472 ierr = PetscFEGetDualSpace(feRef[fieldI], &Qref);CHKERRQ(ierr); 2473 ierr = PetscFEGetNumComponents(feRef[fieldI], &Nc);CHKERRQ(ierr); 2474 } else { 2475 ierr = PetscFVGetDualSpace(fvRef[fieldI], &Qref);CHKERRQ(ierr); 2476 ierr = PetscFVGetNumComponents(fvRef[fieldI], &Nc);CHKERRQ(ierr); 2477 } 2478 ierr = PetscDualSpaceGetDimension(Qref, &fpdim);CHKERRQ(ierr); 2479 for (i = 0; i < fpdim; ++i) { 2480 ierr = PetscDualSpaceGetFunctional(Qref, i, &f);CHKERRQ(ierr); 2481 ierr = PetscQuadratureGetData(f, NULL, NULL, &Np, NULL, NULL);CHKERRQ(ierr); 2482 npoints += Np; 2483 } 2484 ierr = PetscMalloc1(npoints*dim,&points);CHKERRQ(ierr); 2485 for (i = 0, k = 0; i < fpdim; ++i) { 2486 ierr = PetscDualSpaceGetFunctional(Qref, i, &f);CHKERRQ(ierr); 2487 ierr = PetscQuadratureGetData(f, NULL, NULL, &Np, &qpoints, NULL);CHKERRQ(ierr); 2488 for (p = 0; p < Np; ++p, ++k) for (d = 0; d < dim; ++d) points[k*dim+d] = qpoints[p*dim+d]; 2489 } 2490 2491 for (fieldJ = 0, offsetJ = 0; fieldJ < Nf; ++fieldJ) { 2492 PetscObject obj; 2493 PetscClassId id; 2494 PetscInt NcJ = 0, cpdim = 0, j, qNc; 2495 2496 ierr = PetscDSGetDiscretization(cds, fieldJ, &obj);CHKERRQ(ierr); 2497 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 2498 if (id == PETSCFE_CLASSID) { 2499 PetscFE fe = (PetscFE) obj; 2500 PetscTabulation T = NULL; 2501 2502 /* Evaluate basis at points */ 2503 ierr = PetscFEGetNumComponents(fe, &NcJ);CHKERRQ(ierr); 2504 ierr = PetscFEGetDimension(fe, &cpdim);CHKERRQ(ierr); 2505 /* For now, fields only interpolate themselves */ 2506 if (fieldI == fieldJ) { 2507 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); 2508 ierr = PetscFECreateTabulation(fe, 1, npoints, points, 0, &T);CHKERRQ(ierr); 2509 for (i = 0, k = 0; i < fpdim; ++i) { 2510 ierr = PetscDualSpaceGetFunctional(Qref, i, &f);CHKERRQ(ierr); 2511 ierr = PetscQuadratureGetData(f, NULL, &qNc, &Np, NULL, &qweights);CHKERRQ(ierr); 2512 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); 2513 for (p = 0; p < Np; ++p, ++k) { 2514 for (j = 0; j < cpdim; ++j) { 2515 /* 2516 cTotDim: Total columns in element interpolation matrix, sum of number of dual basis functionals in each field 2517 offsetI, offsetJ: Offsets into the larger element interpolation matrix for different fields 2518 fpdim, i, cpdim, j: Dofs for fine and coarse grids, correspond to dual space basis functionals 2519 qNC, Nc, Ncj, c: Number of components in this field 2520 Np, p: Number of quad points in the fine grid functional i 2521 k: i*Np + p, overall point number for the interpolation 2522 */ 2523 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]; 2524 } 2525 } 2526 } 2527 ierr = PetscTabulationDestroy(&T);CHKERRQ(ierr);CHKERRQ(ierr); 2528 } 2529 } else if (id == PETSCFV_CLASSID) { 2530 PetscFV fv = (PetscFV) obj; 2531 2532 /* Evaluate constant function at points */ 2533 ierr = PetscFVGetNumComponents(fv, &NcJ);CHKERRQ(ierr); 2534 cpdim = 1; 2535 /* For now, fields only interpolate themselves */ 2536 if (fieldI == fieldJ) { 2537 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); 2538 for (i = 0, k = 0; i < fpdim; ++i) { 2539 ierr = PetscDualSpaceGetFunctional(Qref, i, &f);CHKERRQ(ierr); 2540 ierr = PetscQuadratureGetData(f, NULL, &qNc, &Np, NULL, &qweights);CHKERRQ(ierr); 2541 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); 2542 for (p = 0; p < Np; ++p, ++k) { 2543 for (j = 0; j < cpdim; ++j) { 2544 for (c = 0; c < Nc; ++c) elemMat[(offsetI + i)*cTotDim + offsetJ + j] += 1.0*qweights[p*qNc+c]; 2545 } 2546 } 2547 } 2548 } 2549 } 2550 offsetJ += cpdim; 2551 } 2552 offsetI += fpdim; 2553 ierr = PetscFree(points);CHKERRQ(ierr); 2554 } 2555 if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(0, name, rTotDim, cTotDim, elemMat);CHKERRQ(ierr);} 2556 /* Preallocate matrix */ 2557 { 2558 Mat preallocator; 2559 PetscScalar *vals; 2560 PetscInt *cellCIndices, *cellFIndices; 2561 PetscInt locRows, locCols, cell; 2562 2563 ierr = MatGetLocalSize(In, &locRows, &locCols);CHKERRQ(ierr); 2564 ierr = MatCreate(PetscObjectComm((PetscObject) In), &preallocator);CHKERRQ(ierr); 2565 ierr = MatSetType(preallocator, MATPREALLOCATOR);CHKERRQ(ierr); 2566 ierr = MatSetSizes(preallocator, locRows, locCols, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr); 2567 ierr = MatSetUp(preallocator);CHKERRQ(ierr); 2568 ierr = PetscCalloc3(rTotDim*cTotDim, &vals,cTotDim,&cellCIndices,rTotDim,&cellFIndices);CHKERRQ(ierr); 2569 for (cell = cStart; cell < cEnd; ++cell) { 2570 if (isRefined) { 2571 ierr = DMPlexMatGetClosureIndicesRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, cell, cellCIndices, cellFIndices);CHKERRQ(ierr); 2572 ierr = MatSetValues(preallocator, rTotDim, cellFIndices, cTotDim, cellCIndices, vals, INSERT_VALUES);CHKERRQ(ierr); 2573 } else { 2574 ierr = DMPlexMatSetClosureGeneral(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, preallocator, cell, vals, INSERT_VALUES);CHKERRQ(ierr); 2575 } 2576 } 2577 ierr = PetscFree3(vals,cellCIndices,cellFIndices);CHKERRQ(ierr); 2578 ierr = MatAssemblyBegin(preallocator, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 2579 ierr = MatAssemblyEnd(preallocator, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 2580 ierr = MatPreallocatorPreallocate(preallocator, PETSC_TRUE, In);CHKERRQ(ierr); 2581 ierr = MatDestroy(&preallocator);CHKERRQ(ierr); 2582 } 2583 /* Fill matrix */ 2584 ierr = MatZeroEntries(In);CHKERRQ(ierr); 2585 for (c = cStart; c < cEnd; ++c) { 2586 if (isRefined) { 2587 ierr = DMPlexMatSetClosureRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, In, c, elemMat, INSERT_VALUES);CHKERRQ(ierr); 2588 } else { 2589 ierr = DMPlexMatSetClosureGeneral(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, In, c, elemMat, INSERT_VALUES);CHKERRQ(ierr); 2590 } 2591 } 2592 for (f = 0; f < Nf; ++f) {ierr = PetscFEDestroy(&feRef[f]);CHKERRQ(ierr);} 2593 ierr = PetscFree2(feRef,fvRef);CHKERRQ(ierr); 2594 ierr = PetscFree(elemMat);CHKERRQ(ierr); 2595 ierr = MatAssemblyBegin(In, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 2596 ierr = MatAssemblyEnd(In, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 2597 if (mesh->printFEM) { 2598 ierr = PetscPrintf(PetscObjectComm((PetscObject)In), "%s:\n", name);CHKERRQ(ierr); 2599 ierr = MatChop(In, 1.0e-10);CHKERRQ(ierr); 2600 ierr = MatView(In, NULL);CHKERRQ(ierr); 2601 } 2602 ierr = PetscLogEventEnd(DMPLEX_InterpolatorFEM,dmc,dmf,0,0);CHKERRQ(ierr); 2603 PetscFunctionReturn(0); 2604 } 2605 2606 PetscErrorCode DMPlexComputeMassMatrixNested(DM dmc, DM dmf, Mat mass, void *user) 2607 { 2608 SETERRQ(PetscObjectComm((PetscObject) dmc), PETSC_ERR_SUP, "Laziness"); 2609 } 2610 2611 /*@ 2612 DMPlexComputeInterpolatorGeneral - Form the local portion of the interpolation matrix I from the coarse DM to a non-nested fine DM. 2613 2614 Input Parameters: 2615 + dmf - The fine mesh 2616 . dmc - The coarse mesh 2617 - user - The user context 2618 2619 Output Parameter: 2620 . In - The interpolation matrix 2621 2622 Level: developer 2623 2624 .seealso: DMPlexComputeInterpolatorNested(), DMPlexComputeJacobianFEM() 2625 @*/ 2626 PetscErrorCode DMPlexComputeInterpolatorGeneral(DM dmc, DM dmf, Mat In, void *user) 2627 { 2628 DM_Plex *mesh = (DM_Plex *) dmf->data; 2629 const char *name = "Interpolator"; 2630 PetscDS prob; 2631 PetscSection fsection, csection, globalFSection, globalCSection; 2632 PetscHSetIJ ht; 2633 PetscLayout rLayout; 2634 PetscInt *dnz, *onz; 2635 PetscInt locRows, rStart, rEnd; 2636 PetscReal *x, *v0, *J, *invJ, detJ; 2637 PetscReal *v0c, *Jc, *invJc, detJc; 2638 PetscScalar *elemMat; 2639 PetscInt dim, Nf, field, totDim, cStart, cEnd, cell, ccell; 2640 PetscErrorCode ierr; 2641 2642 PetscFunctionBegin; 2643 ierr = PetscLogEventBegin(DMPLEX_InterpolatorFEM,dmc,dmf,0,0);CHKERRQ(ierr); 2644 ierr = DMGetCoordinateDim(dmc, &dim);CHKERRQ(ierr); 2645 ierr = DMGetDS(dmc, &prob);CHKERRQ(ierr); 2646 ierr = PetscDSGetWorkspace(prob, &x, NULL, NULL, NULL, NULL);CHKERRQ(ierr); 2647 ierr = PetscDSGetNumFields(prob, &Nf);CHKERRQ(ierr); 2648 ierr = PetscMalloc3(dim,&v0,dim*dim,&J,dim*dim,&invJ);CHKERRQ(ierr); 2649 ierr = PetscMalloc3(dim,&v0c,dim*dim,&Jc,dim*dim,&invJc);CHKERRQ(ierr); 2650 ierr = DMGetLocalSection(dmf, &fsection);CHKERRQ(ierr); 2651 ierr = DMGetGlobalSection(dmf, &globalFSection);CHKERRQ(ierr); 2652 ierr = DMGetLocalSection(dmc, &csection);CHKERRQ(ierr); 2653 ierr = DMGetGlobalSection(dmc, &globalCSection);CHKERRQ(ierr); 2654 ierr = DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd);CHKERRQ(ierr); 2655 ierr = PetscDSGetTotalDimension(prob, &totDim);CHKERRQ(ierr); 2656 ierr = PetscMalloc1(totDim, &elemMat);CHKERRQ(ierr); 2657 2658 ierr = MatGetLocalSize(In, &locRows, NULL);CHKERRQ(ierr); 2659 ierr = PetscLayoutCreate(PetscObjectComm((PetscObject) In), &rLayout);CHKERRQ(ierr); 2660 ierr = PetscLayoutSetLocalSize(rLayout, locRows);CHKERRQ(ierr); 2661 ierr = PetscLayoutSetBlockSize(rLayout, 1);CHKERRQ(ierr); 2662 ierr = PetscLayoutSetUp(rLayout);CHKERRQ(ierr); 2663 ierr = PetscLayoutGetRange(rLayout, &rStart, &rEnd);CHKERRQ(ierr); 2664 ierr = PetscLayoutDestroy(&rLayout);CHKERRQ(ierr); 2665 ierr = PetscCalloc2(locRows,&dnz,locRows,&onz);CHKERRQ(ierr); 2666 ierr = PetscHSetIJCreate(&ht);CHKERRQ(ierr); 2667 for (field = 0; field < Nf; ++field) { 2668 PetscObject obj; 2669 PetscClassId id; 2670 PetscDualSpace Q = NULL; 2671 PetscQuadrature f; 2672 const PetscReal *qpoints; 2673 PetscInt Nc, Np, fpdim, i, d; 2674 2675 ierr = PetscDSGetDiscretization(prob, field, &obj);CHKERRQ(ierr); 2676 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 2677 if (id == PETSCFE_CLASSID) { 2678 PetscFE fe = (PetscFE) obj; 2679 2680 ierr = PetscFEGetDualSpace(fe, &Q);CHKERRQ(ierr); 2681 ierr = PetscFEGetNumComponents(fe, &Nc);CHKERRQ(ierr); 2682 } else if (id == PETSCFV_CLASSID) { 2683 PetscFV fv = (PetscFV) obj; 2684 2685 ierr = PetscFVGetDualSpace(fv, &Q);CHKERRQ(ierr); 2686 Nc = 1; 2687 } 2688 ierr = PetscDualSpaceGetDimension(Q, &fpdim);CHKERRQ(ierr); 2689 /* For each fine grid cell */ 2690 for (cell = cStart; cell < cEnd; ++cell) { 2691 PetscInt *findices, *cindices; 2692 PetscInt numFIndices, numCIndices; 2693 2694 ierr = DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL);CHKERRQ(ierr); 2695 ierr = DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ);CHKERRQ(ierr); 2696 if (numFIndices != fpdim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fine indices %D != %D dual basis vecs", numFIndices, fpdim); 2697 for (i = 0; i < fpdim; ++i) { 2698 Vec pointVec; 2699 PetscScalar *pV; 2700 PetscSF coarseCellSF = NULL; 2701 const PetscSFNode *coarseCells; 2702 PetscInt numCoarseCells, q, c; 2703 2704 /* Get points from the dual basis functional quadrature */ 2705 ierr = PetscDualSpaceGetFunctional(Q, i, &f);CHKERRQ(ierr); 2706 ierr = PetscQuadratureGetData(f, NULL, NULL, &Np, &qpoints, NULL);CHKERRQ(ierr); 2707 ierr = VecCreateSeq(PETSC_COMM_SELF, Np*dim, &pointVec);CHKERRQ(ierr); 2708 ierr = VecSetBlockSize(pointVec, dim);CHKERRQ(ierr); 2709 ierr = VecGetArray(pointVec, &pV);CHKERRQ(ierr); 2710 for (q = 0; q < Np; ++q) { 2711 const PetscReal xi0[3] = {-1., -1., -1.}; 2712 2713 /* Transform point to real space */ 2714 CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q*dim], x); 2715 for (d = 0; d < dim; ++d) pV[q*dim+d] = x[d]; 2716 } 2717 ierr = VecRestoreArray(pointVec, &pV);CHKERRQ(ierr); 2718 /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */ 2719 /* OPT: Pack all quad points from fine cell */ 2720 ierr = DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF);CHKERRQ(ierr); 2721 ierr = PetscSFViewFromOptions(coarseCellSF, NULL, "-interp_sf_view");CHKERRQ(ierr); 2722 /* Update preallocation info */ 2723 ierr = PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells);CHKERRQ(ierr); 2724 if (numCoarseCells != Np) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Not all closure points located"); 2725 { 2726 PetscHashIJKey key; 2727 PetscBool missing; 2728 2729 key.i = findices[i]; 2730 if (key.i >= 0) { 2731 /* Get indices for coarse elements */ 2732 for (ccell = 0; ccell < numCoarseCells; ++ccell) { 2733 ierr = DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL);CHKERRQ(ierr); 2734 for (c = 0; c < numCIndices; ++c) { 2735 key.j = cindices[c]; 2736 if (key.j < 0) continue; 2737 ierr = PetscHSetIJQueryAdd(ht, key, &missing);CHKERRQ(ierr); 2738 if (missing) { 2739 if ((key.j >= rStart) && (key.j < rEnd)) ++dnz[key.i-rStart]; 2740 else ++onz[key.i-rStart]; 2741 } 2742 } 2743 ierr = DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL);CHKERRQ(ierr); 2744 } 2745 } 2746 } 2747 ierr = PetscSFDestroy(&coarseCellSF);CHKERRQ(ierr); 2748 ierr = VecDestroy(&pointVec);CHKERRQ(ierr); 2749 } 2750 ierr = DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL);CHKERRQ(ierr); 2751 } 2752 } 2753 ierr = PetscHSetIJDestroy(&ht);CHKERRQ(ierr); 2754 ierr = MatXAIJSetPreallocation(In, 1, dnz, onz, NULL, NULL);CHKERRQ(ierr); 2755 ierr = MatSetOption(In, MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr); 2756 ierr = PetscFree2(dnz,onz);CHKERRQ(ierr); 2757 for (field = 0; field < Nf; ++field) { 2758 PetscObject obj; 2759 PetscClassId id; 2760 PetscDualSpace Q = NULL; 2761 PetscTabulation T = NULL; 2762 PetscQuadrature f; 2763 const PetscReal *qpoints, *qweights; 2764 PetscInt Nc, qNc, Np, fpdim, i, d; 2765 2766 ierr = PetscDSGetDiscretization(prob, field, &obj);CHKERRQ(ierr); 2767 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 2768 if (id == PETSCFE_CLASSID) { 2769 PetscFE fe = (PetscFE) obj; 2770 2771 ierr = PetscFEGetDualSpace(fe, &Q);CHKERRQ(ierr); 2772 ierr = PetscFEGetNumComponents(fe, &Nc);CHKERRQ(ierr); 2773 ierr = PetscFECreateTabulation(fe, 1, 1, x, 0, &T);CHKERRQ(ierr); 2774 } else if (id == PETSCFV_CLASSID) { 2775 PetscFV fv = (PetscFV) obj; 2776 2777 ierr = PetscFVGetDualSpace(fv, &Q);CHKERRQ(ierr); 2778 Nc = 1; 2779 } else SETERRQ1(PetscObjectComm((PetscObject)dmc),PETSC_ERR_ARG_WRONG,"Unknown discretization type for field %D",field); 2780 ierr = PetscDualSpaceGetDimension(Q, &fpdim);CHKERRQ(ierr); 2781 /* For each fine grid cell */ 2782 for (cell = cStart; cell < cEnd; ++cell) { 2783 PetscInt *findices, *cindices; 2784 PetscInt numFIndices, numCIndices; 2785 2786 ierr = DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL);CHKERRQ(ierr); 2787 ierr = DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ);CHKERRQ(ierr); 2788 if (numFIndices != fpdim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fine indices %D != %D dual basis vecs", numFIndices, fpdim); 2789 for (i = 0; i < fpdim; ++i) { 2790 Vec pointVec; 2791 PetscScalar *pV; 2792 PetscSF coarseCellSF = NULL; 2793 const PetscSFNode *coarseCells; 2794 PetscInt numCoarseCells, cpdim, q, c, j; 2795 2796 /* Get points from the dual basis functional quadrature */ 2797 ierr = PetscDualSpaceGetFunctional(Q, i, &f);CHKERRQ(ierr); 2798 ierr = PetscQuadratureGetData(f, NULL, &qNc, &Np, &qpoints, &qweights);CHKERRQ(ierr); 2799 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); 2800 ierr = VecCreateSeq(PETSC_COMM_SELF, Np*dim, &pointVec);CHKERRQ(ierr); 2801 ierr = VecSetBlockSize(pointVec, dim);CHKERRQ(ierr); 2802 ierr = VecGetArray(pointVec, &pV);CHKERRQ(ierr); 2803 for (q = 0; q < Np; ++q) { 2804 const PetscReal xi0[3] = {-1., -1., -1.}; 2805 2806 /* Transform point to real space */ 2807 CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q*dim], x); 2808 for (d = 0; d < dim; ++d) pV[q*dim+d] = x[d]; 2809 } 2810 ierr = VecRestoreArray(pointVec, &pV);CHKERRQ(ierr); 2811 /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */ 2812 /* OPT: Read this out from preallocation information */ 2813 ierr = DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF);CHKERRQ(ierr); 2814 /* Update preallocation info */ 2815 ierr = PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells);CHKERRQ(ierr); 2816 if (numCoarseCells != Np) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Not all closure points located"); 2817 ierr = VecGetArray(pointVec, &pV);CHKERRQ(ierr); 2818 for (ccell = 0; ccell < numCoarseCells; ++ccell) { 2819 PetscReal pVReal[3]; 2820 const PetscReal xi0[3] = {-1., -1., -1.}; 2821 2822 ierr = DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL);CHKERRQ(ierr); 2823 /* Transform points from real space to coarse reference space */ 2824 ierr = DMPlexComputeCellGeometryFEM(dmc, coarseCells[ccell].index, NULL, v0c, Jc, invJc, &detJc);CHKERRQ(ierr); 2825 for (d = 0; d < dim; ++d) pVReal[d] = PetscRealPart(pV[ccell*dim+d]); 2826 CoordinatesRealToRef(dim, dim, xi0, v0c, invJc, pVReal, x); 2827 2828 if (id == PETSCFE_CLASSID) { 2829 PetscFE fe = (PetscFE) obj; 2830 2831 /* Evaluate coarse basis on contained point */ 2832 ierr = PetscFEGetDimension(fe, &cpdim);CHKERRQ(ierr); 2833 ierr = PetscFEComputeTabulation(fe, 1, x, 0, T);CHKERRQ(ierr); 2834 ierr = PetscArrayzero(elemMat, cpdim);CHKERRQ(ierr); 2835 /* Get elemMat entries by multiplying by weight */ 2836 for (j = 0; j < cpdim; ++j) { 2837 for (c = 0; c < Nc; ++c) elemMat[j] += T->T[0][j*Nc + c]*qweights[ccell*qNc + c]; 2838 } 2839 } else { 2840 cpdim = 1; 2841 for (j = 0; j < cpdim; ++j) { 2842 for (c = 0; c < Nc; ++c) elemMat[j] += 1.0*qweights[ccell*qNc + c]; 2843 } 2844 } 2845 /* Update interpolator */ 2846 if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat);CHKERRQ(ierr);} 2847 if (numCIndices != cpdim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %D != %D", numCIndices, cpdim); 2848 ierr = MatSetValues(In, 1, &findices[i], numCIndices, cindices, elemMat, INSERT_VALUES);CHKERRQ(ierr); 2849 ierr = DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL);CHKERRQ(ierr); 2850 } 2851 ierr = VecRestoreArray(pointVec, &pV);CHKERRQ(ierr); 2852 ierr = PetscSFDestroy(&coarseCellSF);CHKERRQ(ierr); 2853 ierr = VecDestroy(&pointVec);CHKERRQ(ierr); 2854 } 2855 ierr = DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL);CHKERRQ(ierr); 2856 } 2857 if (id == PETSCFE_CLASSID) {ierr = PetscTabulationDestroy(&T);CHKERRQ(ierr);} 2858 } 2859 ierr = PetscFree3(v0,J,invJ);CHKERRQ(ierr); 2860 ierr = PetscFree3(v0c,Jc,invJc);CHKERRQ(ierr); 2861 ierr = PetscFree(elemMat);CHKERRQ(ierr); 2862 ierr = MatAssemblyBegin(In, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 2863 ierr = MatAssemblyEnd(In, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 2864 ierr = PetscLogEventEnd(DMPLEX_InterpolatorFEM,dmc,dmf,0,0);CHKERRQ(ierr); 2865 PetscFunctionReturn(0); 2866 } 2867 2868 /*@ 2869 DMPlexComputeMassMatrixGeneral - Form the local portion of the mass matrix M from the coarse DM to a non-nested fine DM. 2870 2871 Input Parameters: 2872 + dmf - The fine mesh 2873 . dmc - The coarse mesh 2874 - user - The user context 2875 2876 Output Parameter: 2877 . mass - The mass matrix 2878 2879 Level: developer 2880 2881 .seealso: DMPlexComputeMassMatrixNested(), DMPlexComputeInterpolatorNested(), DMPlexComputeInterpolatorGeneral(), DMPlexComputeJacobianFEM() 2882 @*/ 2883 PetscErrorCode DMPlexComputeMassMatrixGeneral(DM dmc, DM dmf, Mat mass, void *user) 2884 { 2885 DM_Plex *mesh = (DM_Plex *) dmf->data; 2886 const char *name = "Mass Matrix"; 2887 PetscDS prob; 2888 PetscSection fsection, csection, globalFSection, globalCSection; 2889 PetscHSetIJ ht; 2890 PetscLayout rLayout; 2891 PetscInt *dnz, *onz; 2892 PetscInt locRows, rStart, rEnd; 2893 PetscReal *x, *v0, *J, *invJ, detJ; 2894 PetscReal *v0c, *Jc, *invJc, detJc; 2895 PetscScalar *elemMat; 2896 PetscInt dim, Nf, field, totDim, cStart, cEnd, cell, ccell; 2897 PetscErrorCode ierr; 2898 2899 PetscFunctionBegin; 2900 ierr = DMGetCoordinateDim(dmc, &dim);CHKERRQ(ierr); 2901 ierr = DMGetDS(dmc, &prob);CHKERRQ(ierr); 2902 ierr = PetscDSGetWorkspace(prob, &x, NULL, NULL, NULL, NULL);CHKERRQ(ierr); 2903 ierr = PetscDSGetNumFields(prob, &Nf);CHKERRQ(ierr); 2904 ierr = PetscMalloc3(dim,&v0,dim*dim,&J,dim*dim,&invJ);CHKERRQ(ierr); 2905 ierr = PetscMalloc3(dim,&v0c,dim*dim,&Jc,dim*dim,&invJc);CHKERRQ(ierr); 2906 ierr = DMGetLocalSection(dmf, &fsection);CHKERRQ(ierr); 2907 ierr = DMGetGlobalSection(dmf, &globalFSection);CHKERRQ(ierr); 2908 ierr = DMGetLocalSection(dmc, &csection);CHKERRQ(ierr); 2909 ierr = DMGetGlobalSection(dmc, &globalCSection);CHKERRQ(ierr); 2910 ierr = DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd);CHKERRQ(ierr); 2911 ierr = PetscDSGetTotalDimension(prob, &totDim);CHKERRQ(ierr); 2912 ierr = PetscMalloc1(totDim, &elemMat);CHKERRQ(ierr); 2913 2914 ierr = MatGetLocalSize(mass, &locRows, NULL);CHKERRQ(ierr); 2915 ierr = PetscLayoutCreate(PetscObjectComm((PetscObject) mass), &rLayout);CHKERRQ(ierr); 2916 ierr = PetscLayoutSetLocalSize(rLayout, locRows);CHKERRQ(ierr); 2917 ierr = PetscLayoutSetBlockSize(rLayout, 1);CHKERRQ(ierr); 2918 ierr = PetscLayoutSetUp(rLayout);CHKERRQ(ierr); 2919 ierr = PetscLayoutGetRange(rLayout, &rStart, &rEnd);CHKERRQ(ierr); 2920 ierr = PetscLayoutDestroy(&rLayout);CHKERRQ(ierr); 2921 ierr = PetscCalloc2(locRows,&dnz,locRows,&onz);CHKERRQ(ierr); 2922 ierr = PetscHSetIJCreate(&ht);CHKERRQ(ierr); 2923 for (field = 0; field < Nf; ++field) { 2924 PetscObject obj; 2925 PetscClassId id; 2926 PetscQuadrature quad; 2927 const PetscReal *qpoints; 2928 PetscInt Nq, Nc, i, d; 2929 2930 ierr = PetscDSGetDiscretization(prob, field, &obj);CHKERRQ(ierr); 2931 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 2932 if (id == PETSCFE_CLASSID) {ierr = PetscFEGetQuadrature((PetscFE) obj, &quad);CHKERRQ(ierr);} 2933 else {ierr = PetscFVGetQuadrature((PetscFV) obj, &quad);CHKERRQ(ierr);} 2934 ierr = PetscQuadratureGetData(quad, NULL, &Nc, &Nq, &qpoints, NULL);CHKERRQ(ierr); 2935 /* For each fine grid cell */ 2936 for (cell = cStart; cell < cEnd; ++cell) { 2937 Vec pointVec; 2938 PetscScalar *pV; 2939 PetscSF coarseCellSF = NULL; 2940 const PetscSFNode *coarseCells; 2941 PetscInt numCoarseCells, q, c; 2942 PetscInt *findices, *cindices; 2943 PetscInt numFIndices, numCIndices; 2944 2945 ierr = DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL);CHKERRQ(ierr); 2946 ierr = DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ);CHKERRQ(ierr); 2947 /* Get points from the quadrature */ 2948 ierr = VecCreateSeq(PETSC_COMM_SELF, Nq*dim, &pointVec);CHKERRQ(ierr); 2949 ierr = VecSetBlockSize(pointVec, dim);CHKERRQ(ierr); 2950 ierr = VecGetArray(pointVec, &pV);CHKERRQ(ierr); 2951 for (q = 0; q < Nq; ++q) { 2952 const PetscReal xi0[3] = {-1., -1., -1.}; 2953 2954 /* Transform point to real space */ 2955 CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q*dim], x); 2956 for (d = 0; d < dim; ++d) pV[q*dim+d] = x[d]; 2957 } 2958 ierr = VecRestoreArray(pointVec, &pV);CHKERRQ(ierr); 2959 /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */ 2960 ierr = DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF);CHKERRQ(ierr); 2961 ierr = PetscSFViewFromOptions(coarseCellSF, NULL, "-interp_sf_view");CHKERRQ(ierr); 2962 /* Update preallocation info */ 2963 ierr = PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells);CHKERRQ(ierr); 2964 if (numCoarseCells != Nq) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Not all closure points located"); 2965 { 2966 PetscHashIJKey key; 2967 PetscBool missing; 2968 2969 for (i = 0; i < numFIndices; ++i) { 2970 key.i = findices[i]; 2971 if (key.i >= 0) { 2972 /* Get indices for coarse elements */ 2973 for (ccell = 0; ccell < numCoarseCells; ++ccell) { 2974 ierr = DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL);CHKERRQ(ierr); 2975 for (c = 0; c < numCIndices; ++c) { 2976 key.j = cindices[c]; 2977 if (key.j < 0) continue; 2978 ierr = PetscHSetIJQueryAdd(ht, key, &missing);CHKERRQ(ierr); 2979 if (missing) { 2980 if ((key.j >= rStart) && (key.j < rEnd)) ++dnz[key.i-rStart]; 2981 else ++onz[key.i-rStart]; 2982 } 2983 } 2984 ierr = DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL);CHKERRQ(ierr); 2985 } 2986 } 2987 } 2988 } 2989 ierr = PetscSFDestroy(&coarseCellSF);CHKERRQ(ierr); 2990 ierr = VecDestroy(&pointVec);CHKERRQ(ierr); 2991 ierr = DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL);CHKERRQ(ierr); 2992 } 2993 } 2994 ierr = PetscHSetIJDestroy(&ht);CHKERRQ(ierr); 2995 ierr = MatXAIJSetPreallocation(mass, 1, dnz, onz, NULL, NULL);CHKERRQ(ierr); 2996 ierr = MatSetOption(mass, MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr); 2997 ierr = PetscFree2(dnz,onz);CHKERRQ(ierr); 2998 for (field = 0; field < Nf; ++field) { 2999 PetscObject obj; 3000 PetscClassId id; 3001 PetscTabulation T, Tfine; 3002 PetscQuadrature quad; 3003 const PetscReal *qpoints, *qweights; 3004 PetscInt Nq, Nc, i, d; 3005 3006 ierr = PetscDSGetDiscretization(prob, field, &obj);CHKERRQ(ierr); 3007 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 3008 if (id == PETSCFE_CLASSID) { 3009 ierr = PetscFEGetQuadrature((PetscFE) obj, &quad);CHKERRQ(ierr); 3010 ierr = PetscFEGetCellTabulation((PetscFE) obj, &Tfine);CHKERRQ(ierr); 3011 ierr = PetscFECreateTabulation((PetscFE) obj, 1, 1, x, 0, &T);CHKERRQ(ierr); 3012 } else { 3013 ierr = PetscFVGetQuadrature((PetscFV) obj, &quad);CHKERRQ(ierr); 3014 } 3015 ierr = PetscQuadratureGetData(quad, NULL, &Nc, &Nq, &qpoints, &qweights);CHKERRQ(ierr); 3016 /* For each fine grid cell */ 3017 for (cell = cStart; cell < cEnd; ++cell) { 3018 Vec pointVec; 3019 PetscScalar *pV; 3020 PetscSF coarseCellSF = NULL; 3021 const PetscSFNode *coarseCells; 3022 PetscInt numCoarseCells, cpdim, q, c, j; 3023 PetscInt *findices, *cindices; 3024 PetscInt numFIndices, numCIndices; 3025 3026 ierr = DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL);CHKERRQ(ierr); 3027 ierr = DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ);CHKERRQ(ierr); 3028 /* Get points from the quadrature */ 3029 ierr = VecCreateSeq(PETSC_COMM_SELF, Nq*dim, &pointVec);CHKERRQ(ierr); 3030 ierr = VecSetBlockSize(pointVec, dim);CHKERRQ(ierr); 3031 ierr = VecGetArray(pointVec, &pV);CHKERRQ(ierr); 3032 for (q = 0; q < Nq; ++q) { 3033 const PetscReal xi0[3] = {-1., -1., -1.}; 3034 3035 /* Transform point to real space */ 3036 CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q*dim], x); 3037 for (d = 0; d < dim; ++d) pV[q*dim+d] = x[d]; 3038 } 3039 ierr = VecRestoreArray(pointVec, &pV);CHKERRQ(ierr); 3040 /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */ 3041 ierr = DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF);CHKERRQ(ierr); 3042 /* Update matrix */ 3043 ierr = PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells);CHKERRQ(ierr); 3044 if (numCoarseCells != Nq) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Not all closure points located"); 3045 ierr = VecGetArray(pointVec, &pV);CHKERRQ(ierr); 3046 for (ccell = 0; ccell < numCoarseCells; ++ccell) { 3047 PetscReal pVReal[3]; 3048 const PetscReal xi0[3] = {-1., -1., -1.}; 3049 3050 3051 ierr = DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL);CHKERRQ(ierr); 3052 /* Transform points from real space to coarse reference space */ 3053 ierr = DMPlexComputeCellGeometryFEM(dmc, coarseCells[ccell].index, NULL, v0c, Jc, invJc, &detJc);CHKERRQ(ierr); 3054 for (d = 0; d < dim; ++d) pVReal[d] = PetscRealPart(pV[ccell*dim+d]); 3055 CoordinatesRealToRef(dim, dim, xi0, v0c, invJc, pVReal, x); 3056 3057 if (id == PETSCFE_CLASSID) { 3058 PetscFE fe = (PetscFE) obj; 3059 3060 /* Evaluate coarse basis on contained point */ 3061 ierr = PetscFEGetDimension(fe, &cpdim);CHKERRQ(ierr); 3062 ierr = PetscFEComputeTabulation(fe, 1, x, 0, T);CHKERRQ(ierr); 3063 /* Get elemMat entries by multiplying by weight */ 3064 for (i = 0; i < numFIndices; ++i) { 3065 ierr = PetscArrayzero(elemMat, cpdim);CHKERRQ(ierr); 3066 for (j = 0; j < cpdim; ++j) { 3067 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; 3068 } 3069 /* Update interpolator */ 3070 if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat);CHKERRQ(ierr);} 3071 if (numCIndices != cpdim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %D != %D", numCIndices, cpdim); 3072 ierr = MatSetValues(mass, 1, &findices[i], numCIndices, cindices, elemMat, ADD_VALUES);CHKERRQ(ierr); 3073 } 3074 } else { 3075 cpdim = 1; 3076 for (i = 0; i < numFIndices; ++i) { 3077 ierr = PetscArrayzero(elemMat, cpdim);CHKERRQ(ierr); 3078 for (j = 0; j < cpdim; ++j) { 3079 for (c = 0; c < Nc; ++c) elemMat[j] += 1.0*1.0*qweights[ccell*Nc + c]*detJ; 3080 } 3081 /* Update interpolator */ 3082 if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat);CHKERRQ(ierr);} 3083 ierr = PetscPrintf(PETSC_COMM_SELF, "Nq: %D %D Nf: %D %D Nc: %D %D\n", ccell, Nq, i, numFIndices, j, numCIndices);CHKERRQ(ierr); 3084 if (numCIndices != cpdim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %D != %D", numCIndices, cpdim); 3085 ierr = MatSetValues(mass, 1, &findices[i], numCIndices, cindices, elemMat, ADD_VALUES);CHKERRQ(ierr); 3086 } 3087 } 3088 ierr = DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, PETSC_FALSE, &numCIndices, &cindices, NULL, NULL);CHKERRQ(ierr); 3089 } 3090 ierr = VecRestoreArray(pointVec, &pV);CHKERRQ(ierr); 3091 ierr = PetscSFDestroy(&coarseCellSF);CHKERRQ(ierr); 3092 ierr = VecDestroy(&pointVec);CHKERRQ(ierr); 3093 ierr = DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, PETSC_FALSE, &numFIndices, &findices, NULL, NULL);CHKERRQ(ierr); 3094 } 3095 if (id == PETSCFE_CLASSID) {ierr = PetscTabulationDestroy(&T);CHKERRQ(ierr);} 3096 } 3097 ierr = PetscFree3(v0,J,invJ);CHKERRQ(ierr); 3098 ierr = PetscFree3(v0c,Jc,invJc);CHKERRQ(ierr); 3099 ierr = PetscFree(elemMat);CHKERRQ(ierr); 3100 ierr = MatAssemblyBegin(mass, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 3101 ierr = MatAssemblyEnd(mass, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 3102 PetscFunctionReturn(0); 3103 } 3104 3105 /*@ 3106 DMPlexComputeInjectorFEM - Compute a mapping from coarse unknowns to fine unknowns 3107 3108 Input Parameters: 3109 + dmc - The coarse mesh 3110 - dmf - The fine mesh 3111 - user - The user context 3112 3113 Output Parameter: 3114 . sc - The mapping 3115 3116 Level: developer 3117 3118 .seealso: DMPlexComputeInterpolatorNested(), DMPlexComputeJacobianFEM() 3119 @*/ 3120 PetscErrorCode DMPlexComputeInjectorFEM(DM dmc, DM dmf, VecScatter *sc, void *user) 3121 { 3122 PetscDS prob; 3123 PetscFE *feRef; 3124 PetscFV *fvRef; 3125 Vec fv, cv; 3126 IS fis, cis; 3127 PetscSection fsection, fglobalSection, csection, cglobalSection; 3128 PetscInt *cmap, *cellCIndices, *cellFIndices, *cindices, *findices; 3129 PetscInt cTotDim, fTotDim = 0, Nf, f, field, cStart, cEnd, c, dim, d, startC, endC, offsetC, offsetF, m; 3130 PetscBool *needAvg; 3131 PetscErrorCode ierr; 3132 3133 PetscFunctionBegin; 3134 ierr = PetscLogEventBegin(DMPLEX_InjectorFEM,dmc,dmf,0,0);CHKERRQ(ierr); 3135 ierr = DMGetDimension(dmf, &dim);CHKERRQ(ierr); 3136 ierr = DMGetLocalSection(dmf, &fsection);CHKERRQ(ierr); 3137 ierr = DMGetGlobalSection(dmf, &fglobalSection);CHKERRQ(ierr); 3138 ierr = DMGetLocalSection(dmc, &csection);CHKERRQ(ierr); 3139 ierr = DMGetGlobalSection(dmc, &cglobalSection);CHKERRQ(ierr); 3140 ierr = PetscSectionGetNumFields(fsection, &Nf);CHKERRQ(ierr); 3141 ierr = DMPlexGetSimplexOrBoxCells(dmc, 0, &cStart, &cEnd);CHKERRQ(ierr); 3142 ierr = DMGetDS(dmc, &prob);CHKERRQ(ierr); 3143 ierr = PetscCalloc3(Nf,&feRef,Nf,&fvRef,Nf,&needAvg);CHKERRQ(ierr); 3144 for (f = 0; f < Nf; ++f) { 3145 PetscObject obj; 3146 PetscClassId id; 3147 PetscInt fNb = 0, Nc = 0; 3148 3149 ierr = PetscDSGetDiscretization(prob, f, &obj);CHKERRQ(ierr); 3150 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 3151 if (id == PETSCFE_CLASSID) { 3152 PetscFE fe = (PetscFE) obj; 3153 PetscSpace sp; 3154 PetscInt maxDegree; 3155 3156 ierr = PetscFERefine(fe, &feRef[f]);CHKERRQ(ierr); 3157 ierr = PetscFEGetDimension(feRef[f], &fNb);CHKERRQ(ierr); 3158 ierr = PetscFEGetNumComponents(fe, &Nc);CHKERRQ(ierr); 3159 ierr = PetscFEGetBasisSpace(fe, &sp);CHKERRQ(ierr); 3160 ierr = PetscSpaceGetDegree(sp, NULL, &maxDegree);CHKERRQ(ierr); 3161 if (!maxDegree) needAvg[f] = PETSC_TRUE; 3162 } else if (id == PETSCFV_CLASSID) { 3163 PetscFV fv = (PetscFV) obj; 3164 PetscDualSpace Q; 3165 3166 ierr = PetscFVRefine(fv, &fvRef[f]);CHKERRQ(ierr); 3167 ierr = PetscFVGetDualSpace(fvRef[f], &Q);CHKERRQ(ierr); 3168 ierr = PetscDualSpaceGetDimension(Q, &fNb);CHKERRQ(ierr); 3169 ierr = PetscFVGetNumComponents(fv, &Nc);CHKERRQ(ierr); 3170 needAvg[f] = PETSC_TRUE; 3171 } 3172 fTotDim += fNb; 3173 } 3174 ierr = PetscDSGetTotalDimension(prob, &cTotDim);CHKERRQ(ierr); 3175 ierr = PetscMalloc1(cTotDim,&cmap);CHKERRQ(ierr); 3176 for (field = 0, offsetC = 0, offsetF = 0; field < Nf; ++field) { 3177 PetscFE feC; 3178 PetscFV fvC; 3179 PetscDualSpace QF, QC; 3180 PetscInt order = -1, NcF, NcC, fpdim, cpdim; 3181 3182 if (feRef[field]) { 3183 ierr = PetscDSGetDiscretization(prob, field, (PetscObject *) &feC);CHKERRQ(ierr); 3184 ierr = PetscFEGetNumComponents(feC, &NcC);CHKERRQ(ierr); 3185 ierr = PetscFEGetNumComponents(feRef[field], &NcF);CHKERRQ(ierr); 3186 ierr = PetscFEGetDualSpace(feRef[field], &QF);CHKERRQ(ierr); 3187 ierr = PetscDualSpaceGetOrder(QF, &order);CHKERRQ(ierr); 3188 ierr = PetscDualSpaceGetDimension(QF, &fpdim);CHKERRQ(ierr); 3189 ierr = PetscFEGetDualSpace(feC, &QC);CHKERRQ(ierr); 3190 ierr = PetscDualSpaceGetDimension(QC, &cpdim);CHKERRQ(ierr); 3191 } else { 3192 ierr = PetscDSGetDiscretization(prob, field, (PetscObject *) &fvC);CHKERRQ(ierr); 3193 ierr = PetscFVGetNumComponents(fvC, &NcC);CHKERRQ(ierr); 3194 ierr = PetscFVGetNumComponents(fvRef[field], &NcF);CHKERRQ(ierr); 3195 ierr = PetscFVGetDualSpace(fvRef[field], &QF);CHKERRQ(ierr); 3196 ierr = PetscDualSpaceGetDimension(QF, &fpdim);CHKERRQ(ierr); 3197 ierr = PetscFVGetDualSpace(fvC, &QC);CHKERRQ(ierr); 3198 ierr = PetscDualSpaceGetDimension(QC, &cpdim);CHKERRQ(ierr); 3199 } 3200 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); 3201 for (c = 0; c < cpdim; ++c) { 3202 PetscQuadrature cfunc; 3203 const PetscReal *cqpoints, *cqweights; 3204 PetscInt NqcC, NpC; 3205 PetscBool found = PETSC_FALSE; 3206 3207 ierr = PetscDualSpaceGetFunctional(QC, c, &cfunc);CHKERRQ(ierr); 3208 ierr = PetscQuadratureGetData(cfunc, NULL, &NqcC, &NpC, &cqpoints, &cqweights);CHKERRQ(ierr); 3209 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); 3210 if (NpC != 1 && feRef[field]) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Do not know how to do injection for moments"); 3211 for (f = 0; f < fpdim; ++f) { 3212 PetscQuadrature ffunc; 3213 const PetscReal *fqpoints, *fqweights; 3214 PetscReal sum = 0.0; 3215 PetscInt NqcF, NpF; 3216 3217 ierr = PetscDualSpaceGetFunctional(QF, f, &ffunc);CHKERRQ(ierr); 3218 ierr = PetscQuadratureGetData(ffunc, NULL, &NqcF, &NpF, &fqpoints, &fqweights);CHKERRQ(ierr); 3219 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); 3220 if (NpC != NpF) continue; 3221 for (d = 0; d < dim; ++d) sum += PetscAbsReal(cqpoints[d] - fqpoints[d]); 3222 if (sum > 1.0e-9) continue; 3223 for (d = 0; d < NcC; ++d) sum += PetscAbsReal(cqweights[d]*fqweights[d]); 3224 if (sum < 1.0e-9) continue; 3225 cmap[offsetC+c] = offsetF+f; 3226 found = PETSC_TRUE; 3227 break; 3228 } 3229 if (!found) { 3230 /* TODO We really want the average here, but some asshole put VecScatter in the interface */ 3231 if (fvRef[field] || (feRef[field] && order == 0)) { 3232 cmap[offsetC+c] = offsetF+0; 3233 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate matching functional for injection"); 3234 } 3235 } 3236 offsetC += cpdim; 3237 offsetF += fpdim; 3238 } 3239 for (f = 0; f < Nf; ++f) {ierr = PetscFEDestroy(&feRef[f]);CHKERRQ(ierr);ierr = PetscFVDestroy(&fvRef[f]);CHKERRQ(ierr);} 3240 ierr = PetscFree3(feRef,fvRef,needAvg);CHKERRQ(ierr); 3241 3242 ierr = DMGetGlobalVector(dmf, &fv);CHKERRQ(ierr); 3243 ierr = DMGetGlobalVector(dmc, &cv);CHKERRQ(ierr); 3244 ierr = VecGetOwnershipRange(cv, &startC, &endC);CHKERRQ(ierr); 3245 ierr = PetscSectionGetConstrainedStorageSize(cglobalSection, &m);CHKERRQ(ierr); 3246 ierr = PetscMalloc2(cTotDim,&cellCIndices,fTotDim,&cellFIndices);CHKERRQ(ierr); 3247 ierr = PetscMalloc1(m,&cindices);CHKERRQ(ierr); 3248 ierr = PetscMalloc1(m,&findices);CHKERRQ(ierr); 3249 for (d = 0; d < m; ++d) cindices[d] = findices[d] = -1; 3250 for (c = cStart; c < cEnd; ++c) { 3251 ierr = DMPlexMatGetClosureIndicesRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, c, cellCIndices, cellFIndices);CHKERRQ(ierr); 3252 for (d = 0; d < cTotDim; ++d) { 3253 if ((cellCIndices[d] < startC) || (cellCIndices[d] >= endC)) continue; 3254 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]]); 3255 cindices[cellCIndices[d]-startC] = cellCIndices[d]; 3256 findices[cellCIndices[d]-startC] = cellFIndices[cmap[d]]; 3257 } 3258 } 3259 ierr = PetscFree(cmap);CHKERRQ(ierr); 3260 ierr = PetscFree2(cellCIndices,cellFIndices);CHKERRQ(ierr); 3261 3262 ierr = ISCreateGeneral(PETSC_COMM_SELF, m, cindices, PETSC_OWN_POINTER, &cis);CHKERRQ(ierr); 3263 ierr = ISCreateGeneral(PETSC_COMM_SELF, m, findices, PETSC_OWN_POINTER, &fis);CHKERRQ(ierr); 3264 ierr = VecScatterCreate(cv, cis, fv, fis, sc);CHKERRQ(ierr); 3265 ierr = ISDestroy(&cis);CHKERRQ(ierr); 3266 ierr = ISDestroy(&fis);CHKERRQ(ierr); 3267 ierr = DMRestoreGlobalVector(dmf, &fv);CHKERRQ(ierr); 3268 ierr = DMRestoreGlobalVector(dmc, &cv);CHKERRQ(ierr); 3269 ierr = PetscLogEventEnd(DMPLEX_InjectorFEM,dmc,dmf,0,0);CHKERRQ(ierr); 3270 PetscFunctionReturn(0); 3271 } 3272 3273 /*@C 3274 DMPlexGetCellFields - Retrieve the field values values for a chunk of cells 3275 3276 Input Parameters: 3277 + dm - The DM 3278 . cellIS - The cells to include 3279 . locX - A local vector with the solution fields 3280 . locX_t - A local vector with solution field time derivatives, or NULL 3281 - locA - A local vector with auxiliary fields, or NULL 3282 3283 Output Parameters: 3284 + u - The field coefficients 3285 . u_t - The fields derivative coefficients 3286 - a - The auxiliary field coefficients 3287 3288 Level: developer 3289 3290 .seealso: DMPlexGetFaceFields() 3291 @*/ 3292 PetscErrorCode DMPlexGetCellFields(DM dm, IS cellIS, Vec locX, Vec locX_t, Vec locA, PetscScalar **u, PetscScalar **u_t, PetscScalar **a) 3293 { 3294 DM plex, plexA = NULL; 3295 DMEnclosureType encAux; 3296 PetscSection section, sectionAux; 3297 PetscDS prob; 3298 const PetscInt *cells; 3299 PetscInt cStart, cEnd, numCells, totDim, totDimAux, c; 3300 PetscErrorCode ierr; 3301 3302 PetscFunctionBegin; 3303 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3304 PetscValidHeaderSpecific(locX, VEC_CLASSID, 4); 3305 if (locX_t) {PetscValidHeaderSpecific(locX_t, VEC_CLASSID, 5);} 3306 if (locA) {PetscValidHeaderSpecific(locA, VEC_CLASSID, 6);} 3307 PetscValidPointer(u, 7); 3308 PetscValidPointer(u_t, 8); 3309 PetscValidPointer(a, 9); 3310 ierr = DMPlexConvertPlex(dm, &plex, PETSC_FALSE);CHKERRQ(ierr); 3311 ierr = ISGetPointRange(cellIS, &cStart, &cEnd, &cells);CHKERRQ(ierr); 3312 ierr = DMGetLocalSection(dm, §ion);CHKERRQ(ierr); 3313 ierr = DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob);CHKERRQ(ierr); 3314 ierr = PetscDSGetTotalDimension(prob, &totDim);CHKERRQ(ierr); 3315 if (locA) { 3316 DM dmAux; 3317 PetscDS probAux; 3318 3319 ierr = VecGetDM(locA, &dmAux);CHKERRQ(ierr); 3320 ierr = DMGetEnclosureRelation(dmAux, dm, &encAux);CHKERRQ(ierr); 3321 ierr = DMPlexConvertPlex(dmAux, &plexA, PETSC_FALSE);CHKERRQ(ierr); 3322 ierr = DMGetLocalSection(dmAux, §ionAux);CHKERRQ(ierr); 3323 ierr = DMGetDS(dmAux, &probAux);CHKERRQ(ierr); 3324 ierr = PetscDSGetTotalDimension(probAux, &totDimAux);CHKERRQ(ierr); 3325 } 3326 numCells = cEnd - cStart; 3327 ierr = DMGetWorkArray(dm, numCells*totDim, MPIU_SCALAR, u);CHKERRQ(ierr); 3328 if (locX_t) {ierr = DMGetWorkArray(dm, numCells*totDim, MPIU_SCALAR, u_t);CHKERRQ(ierr);} else {*u_t = NULL;} 3329 if (locA) {ierr = DMGetWorkArray(dm, numCells*totDimAux, MPIU_SCALAR, a);CHKERRQ(ierr);} else {*a = NULL;} 3330 for (c = cStart; c < cEnd; ++c) { 3331 const PetscInt cell = cells ? cells[c] : c; 3332 const PetscInt cind = c - cStart; 3333 PetscScalar *x = NULL, *x_t = NULL, *ul = *u, *ul_t = *u_t, *al = *a; 3334 PetscInt i; 3335 3336 ierr = DMPlexVecGetClosure(plex, section, locX, cell, NULL, &x);CHKERRQ(ierr); 3337 for (i = 0; i < totDim; ++i) ul[cind*totDim+i] = x[i]; 3338 ierr = DMPlexVecRestoreClosure(plex, section, locX, cell, NULL, &x);CHKERRQ(ierr); 3339 if (locX_t) { 3340 ierr = DMPlexVecGetClosure(plex, section, locX_t, cell, NULL, &x_t);CHKERRQ(ierr); 3341 for (i = 0; i < totDim; ++i) ul_t[cind*totDim+i] = x_t[i]; 3342 ierr = DMPlexVecRestoreClosure(plex, section, locX_t, cell, NULL, &x_t);CHKERRQ(ierr); 3343 } 3344 if (locA) { 3345 PetscInt subcell; 3346 ierr = DMGetEnclosurePoint(plexA, dm, encAux, cell, &subcell);CHKERRQ(ierr); 3347 ierr = DMPlexVecGetClosure(plexA, sectionAux, locA, subcell, NULL, &x);CHKERRQ(ierr); 3348 for (i = 0; i < totDimAux; ++i) al[cind*totDimAux+i] = x[i]; 3349 ierr = DMPlexVecRestoreClosure(plexA, sectionAux, locA, subcell, NULL, &x);CHKERRQ(ierr); 3350 } 3351 } 3352 ierr = DMDestroy(&plex);CHKERRQ(ierr); 3353 if (locA) {ierr = DMDestroy(&plexA);CHKERRQ(ierr);} 3354 ierr = ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);CHKERRQ(ierr); 3355 PetscFunctionReturn(0); 3356 } 3357 3358 /*@C 3359 DMPlexRestoreCellFields - Restore the field values values for a chunk of cells 3360 3361 Input Parameters: 3362 + dm - The DM 3363 . cellIS - The cells to include 3364 . locX - A local vector with the solution fields 3365 . locX_t - A local vector with solution field time derivatives, or NULL 3366 - locA - A local vector with auxiliary fields, or NULL 3367 3368 Output Parameters: 3369 + u - The field coefficients 3370 . u_t - The fields derivative coefficients 3371 - a - The auxiliary field coefficients 3372 3373 Level: developer 3374 3375 .seealso: DMPlexGetFaceFields() 3376 @*/ 3377 PetscErrorCode DMPlexRestoreCellFields(DM dm, IS cellIS, Vec locX, Vec locX_t, Vec locA, PetscScalar **u, PetscScalar **u_t, PetscScalar **a) 3378 { 3379 PetscErrorCode ierr; 3380 3381 PetscFunctionBegin; 3382 ierr = DMRestoreWorkArray(dm, 0, MPIU_SCALAR, u);CHKERRQ(ierr); 3383 if (locX_t) {ierr = DMRestoreWorkArray(dm, 0, MPIU_SCALAR, u_t);CHKERRQ(ierr);} 3384 if (locA) {ierr = DMRestoreWorkArray(dm, 0, MPIU_SCALAR, a);CHKERRQ(ierr);} 3385 PetscFunctionReturn(0); 3386 } 3387 3388 /*@C 3389 DMPlexGetFaceFields - Retrieve the field values values for a chunk of faces 3390 3391 Input Parameters: 3392 + dm - The DM 3393 . fStart - The first face to include 3394 . fEnd - The first face to exclude 3395 . locX - A local vector with the solution fields 3396 . locX_t - A local vector with solution field time derivatives, or NULL 3397 . faceGeometry - A local vector with face geometry 3398 . cellGeometry - A local vector with cell geometry 3399 - locaGrad - A local vector with field gradients, or NULL 3400 3401 Output Parameters: 3402 + Nface - The number of faces with field values 3403 . uL - The field values at the left side of the face 3404 - uR - The field values at the right side of the face 3405 3406 Level: developer 3407 3408 .seealso: DMPlexGetCellFields() 3409 @*/ 3410 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) 3411 { 3412 DM dmFace, dmCell, dmGrad = NULL; 3413 PetscSection section; 3414 PetscDS prob; 3415 DMLabel ghostLabel; 3416 const PetscScalar *facegeom, *cellgeom, *x, *lgrad; 3417 PetscBool *isFE; 3418 PetscInt dim, Nf, f, Nc, numFaces = fEnd - fStart, iface, face; 3419 PetscErrorCode ierr; 3420 3421 PetscFunctionBegin; 3422 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3423 PetscValidHeaderSpecific(locX, VEC_CLASSID, 4); 3424 if (locX_t) {PetscValidHeaderSpecific(locX_t, VEC_CLASSID, 5);} 3425 PetscValidHeaderSpecific(faceGeometry, VEC_CLASSID, 6); 3426 PetscValidHeaderSpecific(cellGeometry, VEC_CLASSID, 7); 3427 if (locGrad) {PetscValidHeaderSpecific(locGrad, VEC_CLASSID, 8);} 3428 PetscValidPointer(uL, 9); 3429 PetscValidPointer(uR, 10); 3430 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 3431 ierr = DMGetDS(dm, &prob);CHKERRQ(ierr); 3432 ierr = DMGetLocalSection(dm, §ion);CHKERRQ(ierr); 3433 ierr = PetscDSGetNumFields(prob, &Nf);CHKERRQ(ierr); 3434 ierr = PetscDSGetTotalComponents(prob, &Nc);CHKERRQ(ierr); 3435 ierr = PetscMalloc1(Nf, &isFE);CHKERRQ(ierr); 3436 for (f = 0; f < Nf; ++f) { 3437 PetscObject obj; 3438 PetscClassId id; 3439 3440 ierr = PetscDSGetDiscretization(prob, f, &obj);CHKERRQ(ierr); 3441 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 3442 if (id == PETSCFE_CLASSID) {isFE[f] = PETSC_TRUE;} 3443 else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;} 3444 else {isFE[f] = PETSC_FALSE;} 3445 } 3446 ierr = DMGetLabel(dm, "ghost", &ghostLabel);CHKERRQ(ierr); 3447 ierr = VecGetArrayRead(locX, &x);CHKERRQ(ierr); 3448 ierr = VecGetDM(faceGeometry, &dmFace);CHKERRQ(ierr); 3449 ierr = VecGetArrayRead(faceGeometry, &facegeom);CHKERRQ(ierr); 3450 ierr = VecGetDM(cellGeometry, &dmCell);CHKERRQ(ierr); 3451 ierr = VecGetArrayRead(cellGeometry, &cellgeom);CHKERRQ(ierr); 3452 if (locGrad) { 3453 ierr = VecGetDM(locGrad, &dmGrad);CHKERRQ(ierr); 3454 ierr = VecGetArrayRead(locGrad, &lgrad);CHKERRQ(ierr); 3455 } 3456 ierr = DMGetWorkArray(dm, numFaces*Nc, MPIU_SCALAR, uL);CHKERRQ(ierr); 3457 ierr = DMGetWorkArray(dm, numFaces*Nc, MPIU_SCALAR, uR);CHKERRQ(ierr); 3458 /* Right now just eat the extra work for FE (could make a cell loop) */ 3459 for (face = fStart, iface = 0; face < fEnd; ++face) { 3460 const PetscInt *cells; 3461 PetscFVFaceGeom *fg; 3462 PetscFVCellGeom *cgL, *cgR; 3463 PetscScalar *xL, *xR, *gL, *gR; 3464 PetscScalar *uLl = *uL, *uRl = *uR; 3465 PetscInt ghost, nsupp, nchild; 3466 3467 ierr = DMLabelGetValue(ghostLabel, face, &ghost);CHKERRQ(ierr); 3468 ierr = DMPlexGetSupportSize(dm, face, &nsupp);CHKERRQ(ierr); 3469 ierr = DMPlexGetTreeChildren(dm, face, &nchild, NULL);CHKERRQ(ierr); 3470 if (ghost >= 0 || nsupp > 2 || nchild > 0) continue; 3471 ierr = DMPlexPointLocalRead(dmFace, face, facegeom, &fg);CHKERRQ(ierr); 3472 ierr = DMPlexGetSupport(dm, face, &cells);CHKERRQ(ierr); 3473 ierr = DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cgL);CHKERRQ(ierr); 3474 ierr = DMPlexPointLocalRead(dmCell, cells[1], cellgeom, &cgR);CHKERRQ(ierr); 3475 for (f = 0; f < Nf; ++f) { 3476 PetscInt off; 3477 3478 ierr = PetscDSGetComponentOffset(prob, f, &off);CHKERRQ(ierr); 3479 if (isFE[f]) { 3480 const PetscInt *cone; 3481 PetscInt comp, coneSizeL, coneSizeR, faceLocL, faceLocR, ldof, rdof, d; 3482 3483 xL = xR = NULL; 3484 ierr = PetscSectionGetFieldComponents(section, f, &comp);CHKERRQ(ierr); 3485 ierr = DMPlexVecGetClosure(dm, section, locX, cells[0], &ldof, (PetscScalar **) &xL);CHKERRQ(ierr); 3486 ierr = DMPlexVecGetClosure(dm, section, locX, cells[1], &rdof, (PetscScalar **) &xR);CHKERRQ(ierr); 3487 ierr = DMPlexGetCone(dm, cells[0], &cone);CHKERRQ(ierr); 3488 ierr = DMPlexGetConeSize(dm, cells[0], &coneSizeL);CHKERRQ(ierr); 3489 for (faceLocL = 0; faceLocL < coneSizeL; ++faceLocL) if (cone[faceLocL] == face) break; 3490 ierr = DMPlexGetCone(dm, cells[1], &cone);CHKERRQ(ierr); 3491 ierr = DMPlexGetConeSize(dm, cells[1], &coneSizeR);CHKERRQ(ierr); 3492 for (faceLocR = 0; faceLocR < coneSizeR; ++faceLocR) if (cone[faceLocR] == face) break; 3493 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]); 3494 /* Check that FEM field has values in the right cell (sometimes its an FV ghost cell) */ 3495 /* TODO: this is a hack that might not be right for nonconforming */ 3496 if (faceLocL < coneSizeL) { 3497 ierr = PetscFEEvaluateFaceFields_Internal(prob, f, faceLocL, xL, &uLl[iface*Nc+off]);CHKERRQ(ierr); 3498 if (rdof == ldof && faceLocR < coneSizeR) {ierr = PetscFEEvaluateFaceFields_Internal(prob, f, faceLocR, xR, &uRl[iface*Nc+off]);CHKERRQ(ierr);} 3499 else {for (d = 0; d < comp; ++d) uRl[iface*Nc+off+d] = uLl[iface*Nc+off+d];} 3500 } 3501 else { 3502 ierr = PetscFEEvaluateFaceFields_Internal(prob, f, faceLocR, xR, &uRl[iface*Nc+off]);CHKERRQ(ierr); 3503 ierr = PetscSectionGetFieldComponents(section, f, &comp);CHKERRQ(ierr); 3504 for (d = 0; d < comp; ++d) uLl[iface*Nc+off+d] = uRl[iface*Nc+off+d]; 3505 } 3506 ierr = DMPlexVecRestoreClosure(dm, section, locX, cells[0], &ldof, (PetscScalar **) &xL);CHKERRQ(ierr); 3507 ierr = DMPlexVecRestoreClosure(dm, section, locX, cells[1], &rdof, (PetscScalar **) &xR);CHKERRQ(ierr); 3508 } else { 3509 PetscFV fv; 3510 PetscInt numComp, c; 3511 3512 ierr = PetscDSGetDiscretization(prob, f, (PetscObject *) &fv);CHKERRQ(ierr); 3513 ierr = PetscFVGetNumComponents(fv, &numComp);CHKERRQ(ierr); 3514 ierr = DMPlexPointLocalFieldRead(dm, cells[0], f, x, &xL);CHKERRQ(ierr); 3515 ierr = DMPlexPointLocalFieldRead(dm, cells[1], f, x, &xR);CHKERRQ(ierr); 3516 if (dmGrad) { 3517 PetscReal dxL[3], dxR[3]; 3518 3519 ierr = DMPlexPointLocalRead(dmGrad, cells[0], lgrad, &gL);CHKERRQ(ierr); 3520 ierr = DMPlexPointLocalRead(dmGrad, cells[1], lgrad, &gR);CHKERRQ(ierr); 3521 DMPlex_WaxpyD_Internal(dim, -1, cgL->centroid, fg->centroid, dxL); 3522 DMPlex_WaxpyD_Internal(dim, -1, cgR->centroid, fg->centroid, dxR); 3523 for (c = 0; c < numComp; ++c) { 3524 uLl[iface*Nc+off+c] = xL[c] + DMPlex_DotD_Internal(dim, &gL[c*dim], dxL); 3525 uRl[iface*Nc+off+c] = xR[c] + DMPlex_DotD_Internal(dim, &gR[c*dim], dxR); 3526 } 3527 } else { 3528 for (c = 0; c < numComp; ++c) { 3529 uLl[iface*Nc+off+c] = xL[c]; 3530 uRl[iface*Nc+off+c] = xR[c]; 3531 } 3532 } 3533 } 3534 } 3535 ++iface; 3536 } 3537 *Nface = iface; 3538 ierr = VecRestoreArrayRead(locX, &x);CHKERRQ(ierr); 3539 ierr = VecRestoreArrayRead(faceGeometry, &facegeom);CHKERRQ(ierr); 3540 ierr = VecRestoreArrayRead(cellGeometry, &cellgeom);CHKERRQ(ierr); 3541 if (locGrad) { 3542 ierr = VecRestoreArrayRead(locGrad, &lgrad);CHKERRQ(ierr); 3543 } 3544 ierr = PetscFree(isFE);CHKERRQ(ierr); 3545 PetscFunctionReturn(0); 3546 } 3547 3548 /*@C 3549 DMPlexRestoreFaceFields - Restore the field values values for a chunk of faces 3550 3551 Input Parameters: 3552 + dm - The DM 3553 . fStart - The first face to include 3554 . fEnd - The first face to exclude 3555 . locX - A local vector with the solution fields 3556 . locX_t - A local vector with solution field time derivatives, or NULL 3557 . faceGeometry - A local vector with face geometry 3558 . cellGeometry - A local vector with cell geometry 3559 - locaGrad - A local vector with field gradients, or NULL 3560 3561 Output Parameters: 3562 + Nface - The number of faces with field values 3563 . uL - The field values at the left side of the face 3564 - uR - The field values at the right side of the face 3565 3566 Level: developer 3567 3568 .seealso: DMPlexGetFaceFields() 3569 @*/ 3570 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) 3571 { 3572 PetscErrorCode ierr; 3573 3574 PetscFunctionBegin; 3575 ierr = DMRestoreWorkArray(dm, 0, MPIU_SCALAR, uL);CHKERRQ(ierr); 3576 ierr = DMRestoreWorkArray(dm, 0, MPIU_SCALAR, uR);CHKERRQ(ierr); 3577 PetscFunctionReturn(0); 3578 } 3579 3580 /*@C 3581 DMPlexGetFaceGeometry - Retrieve the geometric values for a chunk of faces 3582 3583 Input Parameters: 3584 + dm - The DM 3585 . fStart - The first face to include 3586 . fEnd - The first face to exclude 3587 . faceGeometry - A local vector with face geometry 3588 - cellGeometry - A local vector with cell geometry 3589 3590 Output Parameters: 3591 + Nface - The number of faces with field values 3592 . fgeom - The extract the face centroid and normal 3593 - vol - The cell volume 3594 3595 Level: developer 3596 3597 .seealso: DMPlexGetCellFields() 3598 @*/ 3599 PetscErrorCode DMPlexGetFaceGeometry(DM dm, PetscInt fStart, PetscInt fEnd, Vec faceGeometry, Vec cellGeometry, PetscInt *Nface, PetscFVFaceGeom **fgeom, PetscReal **vol) 3600 { 3601 DM dmFace, dmCell; 3602 DMLabel ghostLabel; 3603 const PetscScalar *facegeom, *cellgeom; 3604 PetscInt dim, numFaces = fEnd - fStart, iface, face; 3605 PetscErrorCode ierr; 3606 3607 PetscFunctionBegin; 3608 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3609 PetscValidHeaderSpecific(faceGeometry, VEC_CLASSID, 4); 3610 PetscValidHeaderSpecific(cellGeometry, VEC_CLASSID, 5); 3611 PetscValidPointer(fgeom, 6); 3612 PetscValidPointer(vol, 7); 3613 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 3614 ierr = DMGetLabel(dm, "ghost", &ghostLabel);CHKERRQ(ierr); 3615 ierr = VecGetDM(faceGeometry, &dmFace);CHKERRQ(ierr); 3616 ierr = VecGetArrayRead(faceGeometry, &facegeom);CHKERRQ(ierr); 3617 ierr = VecGetDM(cellGeometry, &dmCell);CHKERRQ(ierr); 3618 ierr = VecGetArrayRead(cellGeometry, &cellgeom);CHKERRQ(ierr); 3619 ierr = PetscMalloc1(numFaces, fgeom);CHKERRQ(ierr); 3620 ierr = DMGetWorkArray(dm, numFaces*2, MPIU_SCALAR, vol);CHKERRQ(ierr); 3621 for (face = fStart, iface = 0; face < fEnd; ++face) { 3622 const PetscInt *cells; 3623 PetscFVFaceGeom *fg; 3624 PetscFVCellGeom *cgL, *cgR; 3625 PetscFVFaceGeom *fgeoml = *fgeom; 3626 PetscReal *voll = *vol; 3627 PetscInt ghost, d, nchild, nsupp; 3628 3629 ierr = DMLabelGetValue(ghostLabel, face, &ghost);CHKERRQ(ierr); 3630 ierr = DMPlexGetSupportSize(dm, face, &nsupp);CHKERRQ(ierr); 3631 ierr = DMPlexGetTreeChildren(dm, face, &nchild, NULL);CHKERRQ(ierr); 3632 if (ghost >= 0 || nsupp > 2 || nchild > 0) continue; 3633 ierr = DMPlexPointLocalRead(dmFace, face, facegeom, &fg);CHKERRQ(ierr); 3634 ierr = DMPlexGetSupport(dm, face, &cells);CHKERRQ(ierr); 3635 ierr = DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cgL);CHKERRQ(ierr); 3636 ierr = DMPlexPointLocalRead(dmCell, cells[1], cellgeom, &cgR);CHKERRQ(ierr); 3637 for (d = 0; d < dim; ++d) { 3638 fgeoml[iface].centroid[d] = fg->centroid[d]; 3639 fgeoml[iface].normal[d] = fg->normal[d]; 3640 } 3641 voll[iface*2+0] = cgL->volume; 3642 voll[iface*2+1] = cgR->volume; 3643 ++iface; 3644 } 3645 *Nface = iface; 3646 ierr = VecRestoreArrayRead(faceGeometry, &facegeom);CHKERRQ(ierr); 3647 ierr = VecRestoreArrayRead(cellGeometry, &cellgeom);CHKERRQ(ierr); 3648 PetscFunctionReturn(0); 3649 } 3650 3651 /*@C 3652 DMPlexRestoreFaceGeometry - Restore the field values values for a chunk of faces 3653 3654 Input Parameters: 3655 + dm - The DM 3656 . fStart - The first face to include 3657 . fEnd - The first face to exclude 3658 . faceGeometry - A local vector with face geometry 3659 - cellGeometry - A local vector with cell geometry 3660 3661 Output Parameters: 3662 + Nface - The number of faces with field values 3663 . fgeom - The extract the face centroid and normal 3664 - vol - The cell volume 3665 3666 Level: developer 3667 3668 .seealso: DMPlexGetFaceFields() 3669 @*/ 3670 PetscErrorCode DMPlexRestoreFaceGeometry(DM dm, PetscInt fStart, PetscInt fEnd, Vec faceGeometry, Vec cellGeometry, PetscInt *Nface, PetscFVFaceGeom **fgeom, PetscReal **vol) 3671 { 3672 PetscErrorCode ierr; 3673 3674 PetscFunctionBegin; 3675 ierr = PetscFree(*fgeom);CHKERRQ(ierr); 3676 ierr = DMRestoreWorkArray(dm, 0, MPIU_REAL, vol);CHKERRQ(ierr); 3677 PetscFunctionReturn(0); 3678 } 3679 3680 PetscErrorCode DMSNESGetFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom) 3681 { 3682 char composeStr[33] = {0}; 3683 PetscObjectId id; 3684 PetscContainer container; 3685 PetscErrorCode ierr; 3686 3687 PetscFunctionBegin; 3688 ierr = PetscObjectGetId((PetscObject)quad,&id);CHKERRQ(ierr); 3689 ierr = PetscSNPrintf(composeStr, 32, "DMSNESGetFEGeom_%x\n", id);CHKERRQ(ierr); 3690 ierr = PetscObjectQuery((PetscObject) pointIS, composeStr, (PetscObject *) &container);CHKERRQ(ierr); 3691 if (container) { 3692 ierr = PetscContainerGetPointer(container, (void **) geom);CHKERRQ(ierr); 3693 } else { 3694 ierr = DMFieldCreateFEGeom(coordField, pointIS, quad, faceData, geom);CHKERRQ(ierr); 3695 ierr = PetscContainerCreate(PETSC_COMM_SELF,&container);CHKERRQ(ierr); 3696 ierr = PetscContainerSetPointer(container, (void *) *geom);CHKERRQ(ierr); 3697 ierr = PetscContainerSetUserDestroy(container, PetscContainerUserDestroy_PetscFEGeom);CHKERRQ(ierr); 3698 ierr = PetscObjectCompose((PetscObject) pointIS, composeStr, (PetscObject) container);CHKERRQ(ierr); 3699 ierr = PetscContainerDestroy(&container);CHKERRQ(ierr); 3700 } 3701 PetscFunctionReturn(0); 3702 } 3703 3704 PetscErrorCode DMSNESRestoreFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom) 3705 { 3706 PetscFunctionBegin; 3707 *geom = NULL; 3708 PetscFunctionReturn(0); 3709 } 3710 3711 PetscErrorCode DMPlexComputeResidual_Patch_Internal(DM dm, PetscSection section, IS cellIS, PetscReal t, Vec locX, Vec locX_t, Vec locF, void *user) 3712 { 3713 DM_Plex *mesh = (DM_Plex *) dm->data; 3714 const char *name = "Residual"; 3715 DM dmAux = NULL; 3716 DMLabel ghostLabel = NULL; 3717 PetscDS prob = NULL; 3718 PetscDS probAux = NULL; 3719 PetscBool useFEM = PETSC_FALSE; 3720 PetscBool isImplicit = (locX_t || t == PETSC_MIN_REAL) ? PETSC_TRUE : PETSC_FALSE; 3721 DMField coordField = NULL; 3722 Vec locA; 3723 PetscScalar *u = NULL, *u_t, *a, *uL = NULL, *uR = NULL; 3724 IS chunkIS; 3725 const PetscInt *cells; 3726 PetscInt cStart, cEnd, numCells; 3727 PetscInt Nf, f, totDim, totDimAux, numChunks, cellChunkSize, chunk, fStart, fEnd; 3728 PetscInt maxDegree = PETSC_MAX_INT; 3729 PetscQuadrature affineQuad = NULL, *quads = NULL; 3730 PetscFEGeom *affineGeom = NULL, **geoms = NULL; 3731 PetscErrorCode ierr; 3732 3733 PetscFunctionBegin; 3734 ierr = PetscLogEventBegin(DMPLEX_ResidualFEM,dm,0,0,0);CHKERRQ(ierr); 3735 /* FEM+FVM */ 3736 /* 1: Get sizes from dm and dmAux */ 3737 ierr = DMGetLabel(dm, "ghost", &ghostLabel);CHKERRQ(ierr); 3738 ierr = DMGetDS(dm, &prob);CHKERRQ(ierr); 3739 ierr = PetscDSGetNumFields(prob, &Nf);CHKERRQ(ierr); 3740 ierr = PetscDSGetTotalDimension(prob, &totDim);CHKERRQ(ierr); 3741 ierr = PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &locA);CHKERRQ(ierr); 3742 if (locA) { 3743 ierr = VecGetDM(locA, &dmAux);CHKERRQ(ierr); 3744 ierr = DMGetDS(dmAux, &probAux);CHKERRQ(ierr); 3745 ierr = PetscDSGetTotalDimension(probAux, &totDimAux);CHKERRQ(ierr); 3746 } 3747 /* 2: Get geometric data */ 3748 for (f = 0; f < Nf; ++f) { 3749 PetscObject obj; 3750 PetscClassId id; 3751 PetscBool fimp; 3752 3753 ierr = PetscDSGetImplicit(prob, f, &fimp);CHKERRQ(ierr); 3754 if (isImplicit != fimp) continue; 3755 ierr = PetscDSGetDiscretization(prob, f, &obj);CHKERRQ(ierr); 3756 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 3757 if (id == PETSCFE_CLASSID) {useFEM = PETSC_TRUE;} 3758 if (id == PETSCFV_CLASSID) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Use of FVM with PCPATCH not yet implemented"); 3759 } 3760 if (useFEM) { 3761 ierr = DMGetCoordinateField(dm, &coordField);CHKERRQ(ierr); 3762 ierr = DMFieldGetDegree(coordField,cellIS,NULL,&maxDegree);CHKERRQ(ierr); 3763 if (maxDegree <= 1) { 3764 ierr = DMFieldCreateDefaultQuadrature(coordField,cellIS,&affineQuad);CHKERRQ(ierr); 3765 if (affineQuad) { 3766 ierr = DMSNESGetFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom);CHKERRQ(ierr); 3767 } 3768 } else { 3769 ierr = PetscCalloc2(Nf,&quads,Nf,&geoms);CHKERRQ(ierr); 3770 for (f = 0; f < Nf; ++f) { 3771 PetscObject obj; 3772 PetscClassId id; 3773 PetscBool fimp; 3774 3775 ierr = PetscDSGetImplicit(prob, f, &fimp);CHKERRQ(ierr); 3776 if (isImplicit != fimp) continue; 3777 ierr = PetscDSGetDiscretization(prob, f, &obj);CHKERRQ(ierr); 3778 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 3779 if (id == PETSCFE_CLASSID) { 3780 PetscFE fe = (PetscFE) obj; 3781 3782 ierr = PetscFEGetQuadrature(fe, &quads[f]);CHKERRQ(ierr); 3783 ierr = PetscObjectReference((PetscObject)quads[f]);CHKERRQ(ierr); 3784 ierr = DMSNESGetFEGeom(coordField,cellIS,quads[f],PETSC_FALSE,&geoms[f]);CHKERRQ(ierr); 3785 } 3786 } 3787 } 3788 } 3789 /* Loop over chunks */ 3790 ierr = ISGetPointRange(cellIS, &cStart, &cEnd, &cells);CHKERRQ(ierr); 3791 ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr); 3792 if (useFEM) {ierr = ISCreate(PETSC_COMM_SELF, &chunkIS);CHKERRQ(ierr);} 3793 numCells = cEnd - cStart; 3794 numChunks = 1; 3795 cellChunkSize = numCells/numChunks; 3796 numChunks = PetscMin(1,numCells); 3797 for (chunk = 0; chunk < numChunks; ++chunk) { 3798 PetscScalar *elemVec, *fluxL = NULL, *fluxR = NULL; 3799 PetscReal *vol = NULL; 3800 PetscFVFaceGeom *fgeom = NULL; 3801 PetscInt cS = cStart+chunk*cellChunkSize, cE = PetscMin(cS+cellChunkSize, cEnd), numCells = cE - cS, c; 3802 PetscInt numFaces = 0; 3803 3804 /* Extract field coefficients */ 3805 if (useFEM) { 3806 ierr = ISGetPointSubrange(chunkIS, cS, cE, cells);CHKERRQ(ierr); 3807 ierr = DMPlexGetCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a);CHKERRQ(ierr); 3808 ierr = DMGetWorkArray(dm, numCells*totDim, MPIU_SCALAR, &elemVec);CHKERRQ(ierr); 3809 ierr = PetscArrayzero(elemVec, numCells*totDim);CHKERRQ(ierr); 3810 } 3811 /* TODO We will interlace both our field coefficients (u, u_t, uL, uR, etc.) and our output (elemVec, fL, fR). I think this works */ 3812 /* Loop over fields */ 3813 for (f = 0; f < Nf; ++f) { 3814 PetscObject obj; 3815 PetscClassId id; 3816 PetscBool fimp; 3817 PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset; 3818 3819 ierr = PetscDSGetImplicit(prob, f, &fimp);CHKERRQ(ierr); 3820 if (isImplicit != fimp) continue; 3821 ierr = PetscDSGetDiscretization(prob, f, &obj);CHKERRQ(ierr); 3822 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 3823 if (id == PETSCFE_CLASSID) { 3824 PetscFE fe = (PetscFE) obj; 3825 PetscFEGeom *geom = affineGeom ? affineGeom : geoms[f]; 3826 PetscFEGeom *chunkGeom = NULL; 3827 PetscQuadrature quad = affineQuad ? affineQuad : quads[f]; 3828 PetscInt Nq, Nb; 3829 3830 ierr = PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);CHKERRQ(ierr); 3831 ierr = PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL);CHKERRQ(ierr); 3832 ierr = PetscFEGetDimension(fe, &Nb);CHKERRQ(ierr); 3833 blockSize = Nb; 3834 batchSize = numBlocks * blockSize; 3835 ierr = PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);CHKERRQ(ierr); 3836 numChunks = numCells / (numBatches*batchSize); 3837 Ne = numChunks*numBatches*batchSize; 3838 Nr = numCells % (numBatches*batchSize); 3839 offset = numCells - Nr; 3840 /* Integrate FE residual to get elemVec (need fields at quadrature points) */ 3841 /* 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) */ 3842 ierr = PetscFEGeomGetChunk(geom,0,offset,&chunkGeom);CHKERRQ(ierr); 3843 ierr = PetscFEIntegrateResidual(prob, f, Ne, chunkGeom, u, u_t, probAux, a, t, elemVec);CHKERRQ(ierr); 3844 ierr = PetscFEGeomGetChunk(geom,offset,numCells,&chunkGeom);CHKERRQ(ierr); 3845 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); 3846 ierr = PetscFEGeomRestoreChunk(geom,offset,numCells,&chunkGeom);CHKERRQ(ierr); 3847 } else if (id == PETSCFV_CLASSID) { 3848 PetscFV fv = (PetscFV) obj; 3849 3850 Ne = numFaces; 3851 /* Riemann solve over faces (need fields at face centroids) */ 3852 /* We need to evaluate FE fields at those coordinates */ 3853 ierr = PetscFVIntegrateRHSFunction(fv, prob, f, Ne, fgeom, vol, uL, uR, fluxL, fluxR);CHKERRQ(ierr); 3854 } else SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", f); 3855 } 3856 /* Loop over domain */ 3857 if (useFEM) { 3858 /* Add elemVec to locX */ 3859 for (c = cS; c < cE; ++c) { 3860 const PetscInt cell = cells ? cells[c] : c; 3861 const PetscInt cind = c - cStart; 3862 3863 if (mesh->printFEM > 1) {ierr = DMPrintCellVector(cell, name, totDim, &elemVec[cind*totDim]);CHKERRQ(ierr);} 3864 if (ghostLabel) { 3865 PetscInt ghostVal; 3866 3867 ierr = DMLabelGetValue(ghostLabel,cell,&ghostVal);CHKERRQ(ierr); 3868 if (ghostVal > 0) continue; 3869 } 3870 ierr = DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind*totDim], ADD_ALL_VALUES);CHKERRQ(ierr); 3871 } 3872 } 3873 /* Handle time derivative */ 3874 if (locX_t) { 3875 PetscScalar *x_t, *fa; 3876 3877 ierr = VecGetArray(locF, &fa);CHKERRQ(ierr); 3878 ierr = VecGetArray(locX_t, &x_t);CHKERRQ(ierr); 3879 for (f = 0; f < Nf; ++f) { 3880 PetscFV fv; 3881 PetscObject obj; 3882 PetscClassId id; 3883 PetscInt pdim, d; 3884 3885 ierr = PetscDSGetDiscretization(prob, f, &obj);CHKERRQ(ierr); 3886 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 3887 if (id != PETSCFV_CLASSID) continue; 3888 fv = (PetscFV) obj; 3889 ierr = PetscFVGetNumComponents(fv, &pdim);CHKERRQ(ierr); 3890 for (c = cS; c < cE; ++c) { 3891 const PetscInt cell = cells ? cells[c] : c; 3892 PetscScalar *u_t, *r; 3893 3894 if (ghostLabel) { 3895 PetscInt ghostVal; 3896 3897 ierr = DMLabelGetValue(ghostLabel, cell, &ghostVal);CHKERRQ(ierr); 3898 if (ghostVal > 0) continue; 3899 } 3900 ierr = DMPlexPointLocalFieldRead(dm, cell, f, x_t, &u_t);CHKERRQ(ierr); 3901 ierr = DMPlexPointLocalFieldRef(dm, cell, f, fa, &r);CHKERRQ(ierr); 3902 for (d = 0; d < pdim; ++d) r[d] += u_t[d]; 3903 } 3904 } 3905 ierr = VecRestoreArray(locX_t, &x_t);CHKERRQ(ierr); 3906 ierr = VecRestoreArray(locF, &fa);CHKERRQ(ierr); 3907 } 3908 if (useFEM) { 3909 ierr = DMPlexRestoreCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a);CHKERRQ(ierr); 3910 ierr = DMRestoreWorkArray(dm, numCells*totDim, MPIU_SCALAR, &elemVec);CHKERRQ(ierr); 3911 } 3912 } 3913 if (useFEM) {ierr = ISDestroy(&chunkIS);CHKERRQ(ierr);} 3914 ierr = ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);CHKERRQ(ierr); 3915 /* TODO Could include boundary residual here (see DMPlexComputeResidual_Internal) */ 3916 if (useFEM) { 3917 if (maxDegree <= 1) { 3918 ierr = DMSNESRestoreFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom);CHKERRQ(ierr); 3919 ierr = PetscQuadratureDestroy(&affineQuad);CHKERRQ(ierr); 3920 } else { 3921 for (f = 0; f < Nf; ++f) { 3922 ierr = DMSNESRestoreFEGeom(coordField,cellIS,quads[f],PETSC_FALSE,&geoms[f]);CHKERRQ(ierr); 3923 ierr = PetscQuadratureDestroy(&quads[f]);CHKERRQ(ierr); 3924 } 3925 ierr = PetscFree2(quads,geoms);CHKERRQ(ierr); 3926 } 3927 } 3928 ierr = PetscLogEventEnd(DMPLEX_ResidualFEM,dm,0,0,0);CHKERRQ(ierr); 3929 PetscFunctionReturn(0); 3930 } 3931 3932 /* 3933 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 3934 3935 X - The local solution vector 3936 X_t - The local solution time derviative vector, or NULL 3937 */ 3938 PetscErrorCode DMPlexComputeJacobian_Patch_Internal(DM dm, PetscSection section, PetscSection globalSection, IS cellIS, 3939 PetscReal t, PetscReal X_tShift, Vec X, Vec X_t, Mat Jac, Mat JacP, void *ctx) 3940 { 3941 DM_Plex *mesh = (DM_Plex *) dm->data; 3942 const char *name = "Jacobian", *nameP = "JacobianPre"; 3943 DM dmAux = NULL; 3944 PetscDS prob, probAux = NULL; 3945 PetscSection sectionAux = NULL; 3946 Vec A; 3947 DMField coordField; 3948 PetscFEGeom *cgeomFEM; 3949 PetscQuadrature qGeom = NULL; 3950 Mat J = Jac, JP = JacP; 3951 PetscScalar *work, *u = NULL, *u_t = NULL, *a = NULL, *elemMat = NULL, *elemMatP = NULL, *elemMatD = NULL; 3952 PetscBool hasJac, hasPrec, hasDyn, assembleJac, isMatIS, isMatISP, *isFE, hasFV = PETSC_FALSE; 3953 const PetscInt *cells; 3954 PetscInt Nf, fieldI, fieldJ, maxDegree, numCells, cStart, cEnd, numChunks, chunkSize, chunk, totDim, totDimAux = 0, sz, wsz, off = 0, offCell = 0; 3955 PetscErrorCode ierr; 3956 3957 PetscFunctionBegin; 3958 CHKMEMQ; 3959 ierr = ISGetLocalSize(cellIS, &numCells);CHKERRQ(ierr); 3960 ierr = ISGetPointRange(cellIS, &cStart, &cEnd, &cells);CHKERRQ(ierr); 3961 ierr = PetscLogEventBegin(DMPLEX_JacobianFEM,dm,0,0,0);CHKERRQ(ierr); 3962 ierr = DMGetDS(dm, &prob);CHKERRQ(ierr); 3963 ierr = PetscObjectQuery((PetscObject) dm, "dmAux", (PetscObject *) &dmAux);CHKERRQ(ierr); 3964 ierr = PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &A);CHKERRQ(ierr); 3965 if (dmAux) { 3966 ierr = DMGetLocalSection(dmAux, §ionAux);CHKERRQ(ierr); 3967 ierr = DMGetDS(dmAux, &probAux);CHKERRQ(ierr); 3968 } 3969 /* Get flags */ 3970 ierr = PetscDSGetNumFields(prob, &Nf);CHKERRQ(ierr); 3971 ierr = DMGetWorkArray(dm, Nf, MPIU_BOOL, &isFE);CHKERRQ(ierr); 3972 for (fieldI = 0; fieldI < Nf; ++fieldI) { 3973 PetscObject disc; 3974 PetscClassId id; 3975 ierr = PetscDSGetDiscretization(prob, fieldI, &disc);CHKERRQ(ierr); 3976 ierr = PetscObjectGetClassId(disc, &id);CHKERRQ(ierr); 3977 if (id == PETSCFE_CLASSID) {isFE[fieldI] = PETSC_TRUE;} 3978 else if (id == PETSCFV_CLASSID) {hasFV = PETSC_TRUE; isFE[fieldI] = PETSC_FALSE;} 3979 } 3980 ierr = PetscDSHasJacobian(prob, &hasJac);CHKERRQ(ierr); 3981 ierr = PetscDSHasJacobianPreconditioner(prob, &hasPrec);CHKERRQ(ierr); 3982 ierr = PetscDSHasDynamicJacobian(prob, &hasDyn);CHKERRQ(ierr); 3983 assembleJac = hasJac && hasPrec && (Jac != JacP) ? PETSC_TRUE : PETSC_FALSE; 3984 hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE; 3985 ierr = PetscObjectTypeCompare((PetscObject) Jac, MATIS, &isMatIS);CHKERRQ(ierr); 3986 ierr = PetscObjectTypeCompare((PetscObject) JacP, MATIS, &isMatISP);CHKERRQ(ierr); 3987 /* Setup input data and temp arrays (should be DMGetWorkArray) */ 3988 if (isMatISP || isMatISP) {ierr = DMPlexGetSubdomainSection(dm, &globalSection);CHKERRQ(ierr);} 3989 if (isMatIS) {ierr = MatISGetLocalMat(Jac, &J);CHKERRQ(ierr);} 3990 if (isMatISP) {ierr = MatISGetLocalMat(JacP, &JP);CHKERRQ(ierr);} 3991 if (hasFV) {ierr = MatSetOption(JP, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE);CHKERRQ(ierr);} /* No allocated space for FV stuff, so ignore the zero entries */ 3992 ierr = PetscObjectQuery((PetscObject) dm, "dmAux", (PetscObject *) &dmAux);CHKERRQ(ierr); 3993 ierr = PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &A);CHKERRQ(ierr); 3994 ierr = PetscDSGetTotalDimension(prob, &totDim);CHKERRQ(ierr); 3995 if (probAux) {ierr = PetscDSGetTotalDimension(probAux, &totDimAux);CHKERRQ(ierr);} 3996 CHKMEMQ; 3997 /* Compute batch sizes */ 3998 if (isFE[0]) { 3999 PetscFE fe; 4000 PetscQuadrature q; 4001 PetscInt numQuadPoints, numBatches, batchSize, numBlocks, blockSize, Nb; 4002 4003 ierr = PetscDSGetDiscretization(prob, 0, (PetscObject *) &fe);CHKERRQ(ierr); 4004 ierr = PetscFEGetQuadrature(fe, &q);CHKERRQ(ierr); 4005 ierr = PetscQuadratureGetData(q, NULL, NULL, &numQuadPoints, NULL, NULL);CHKERRQ(ierr); 4006 ierr = PetscFEGetDimension(fe, &Nb);CHKERRQ(ierr); 4007 ierr = PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);CHKERRQ(ierr); 4008 blockSize = Nb*numQuadPoints; 4009 batchSize = numBlocks * blockSize; 4010 chunkSize = numBatches * batchSize; 4011 numChunks = numCells / chunkSize + numCells % chunkSize; 4012 ierr = PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);CHKERRQ(ierr); 4013 } else { 4014 chunkSize = numCells; 4015 numChunks = 1; 4016 } 4017 /* Get work space */ 4018 wsz = (((X?1:0) + (X_t?1:0) + (dmAux?1:0))*totDim + ((hasJac?1:0) + (hasPrec?1:0) + (hasDyn?1:0))*totDim*totDim)*chunkSize; 4019 ierr = DMGetWorkArray(dm, wsz, MPIU_SCALAR, &work);CHKERRQ(ierr); 4020 ierr = PetscArrayzero(work, wsz);CHKERRQ(ierr); 4021 off = 0; 4022 u = X ? (sz = chunkSize*totDim, off += sz, work+off-sz) : NULL; 4023 u_t = X_t ? (sz = chunkSize*totDim, off += sz, work+off-sz) : NULL; 4024 a = dmAux ? (sz = chunkSize*totDimAux, off += sz, work+off-sz) : NULL; 4025 elemMat = hasJac ? (sz = chunkSize*totDim*totDim, off += sz, work+off-sz) : NULL; 4026 elemMatP = hasPrec ? (sz = chunkSize*totDim*totDim, off += sz, work+off-sz) : NULL; 4027 elemMatD = hasDyn ? (sz = chunkSize*totDim*totDim, off += sz, work+off-sz) : NULL; 4028 if (off != wsz) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Error is workspace size %D should be %D", off, wsz); 4029 /* Setup geometry */ 4030 ierr = DMGetCoordinateField(dm, &coordField);CHKERRQ(ierr); 4031 ierr = DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree);CHKERRQ(ierr); 4032 if (maxDegree <= 1) {ierr = DMFieldCreateDefaultQuadrature(coordField, cellIS, &qGeom);CHKERRQ(ierr);} 4033 if (!qGeom) { 4034 PetscFE fe; 4035 4036 ierr = PetscDSGetDiscretization(prob, 0, (PetscObject *) &fe);CHKERRQ(ierr); 4037 ierr = PetscFEGetQuadrature(fe, &qGeom);CHKERRQ(ierr); 4038 ierr = PetscObjectReference((PetscObject) qGeom);CHKERRQ(ierr); 4039 } 4040 ierr = DMSNESGetFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM);CHKERRQ(ierr); 4041 /* Compute volume integrals */ 4042 if (assembleJac) {ierr = MatZeroEntries(J);CHKERRQ(ierr);} 4043 ierr = MatZeroEntries(JP);CHKERRQ(ierr); 4044 for (chunk = 0; chunk < numChunks; ++chunk, offCell += chunkSize) { 4045 const PetscInt Ncell = PetscMin(chunkSize, numCells - offCell); 4046 PetscInt c; 4047 4048 /* Extract values */ 4049 for (c = 0; c < Ncell; ++c) { 4050 const PetscInt cell = cells ? cells[c+offCell] : c+offCell; 4051 PetscScalar *x = NULL, *x_t = NULL; 4052 PetscInt i; 4053 4054 if (X) { 4055 ierr = DMPlexVecGetClosure(dm, section, X, cell, NULL, &x);CHKERRQ(ierr); 4056 for (i = 0; i < totDim; ++i) u[c*totDim+i] = x[i]; 4057 ierr = DMPlexVecRestoreClosure(dm, section, X, cell, NULL, &x);CHKERRQ(ierr); 4058 } 4059 if (X_t) { 4060 ierr = DMPlexVecGetClosure(dm, section, X_t, cell, NULL, &x_t);CHKERRQ(ierr); 4061 for (i = 0; i < totDim; ++i) u_t[c*totDim+i] = x_t[i]; 4062 ierr = DMPlexVecRestoreClosure(dm, section, X_t, cell, NULL, &x_t);CHKERRQ(ierr); 4063 } 4064 if (dmAux) { 4065 ierr = DMPlexVecGetClosure(dmAux, sectionAux, A, cell, NULL, &x);CHKERRQ(ierr); 4066 for (i = 0; i < totDimAux; ++i) a[c*totDimAux+i] = x[i]; 4067 ierr = DMPlexVecRestoreClosure(dmAux, sectionAux, A, cell, NULL, &x);CHKERRQ(ierr); 4068 } 4069 } 4070 CHKMEMQ; 4071 for (fieldI = 0; fieldI < Nf; ++fieldI) { 4072 PetscFE fe; 4073 ierr = PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fe);CHKERRQ(ierr); 4074 for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 4075 if (hasJac) {ierr = PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, fieldI, fieldJ, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMat);CHKERRQ(ierr);} 4076 if (hasPrec) {ierr = PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, fieldI, fieldJ, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMatP);CHKERRQ(ierr);} 4077 if (hasDyn) {ierr = PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, fieldI, fieldJ, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMatD);CHKERRQ(ierr);} 4078 } 4079 /* For finite volume, add the identity */ 4080 if (!isFE[fieldI]) { 4081 PetscFV fv; 4082 PetscInt eOffset = 0, Nc, fc, foff; 4083 4084 ierr = PetscDSGetFieldOffset(prob, fieldI, &foff);CHKERRQ(ierr); 4085 ierr = PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fv);CHKERRQ(ierr); 4086 ierr = PetscFVGetNumComponents(fv, &Nc);CHKERRQ(ierr); 4087 for (c = 0; c < chunkSize; ++c, eOffset += totDim*totDim) { 4088 for (fc = 0; fc < Nc; ++fc) { 4089 const PetscInt i = foff + fc; 4090 if (hasJac) {elemMat [eOffset+i*totDim+i] = 1.0;} 4091 if (hasPrec) {elemMatP[eOffset+i*totDim+i] = 1.0;} 4092 } 4093 } 4094 } 4095 } 4096 CHKMEMQ; 4097 /* Add contribution from X_t */ 4098 if (hasDyn) {for (c = 0; c < chunkSize*totDim*totDim; ++c) elemMat[c] += X_tShift*elemMatD[c];} 4099 /* Insert values into matrix */ 4100 for (c = 0; c < Ncell; ++c) { 4101 const PetscInt cell = cells ? cells[c+offCell] : c+offCell; 4102 if (mesh->printFEM > 1) { 4103 if (hasJac) {ierr = DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[(c-cStart)*totDim*totDim]);CHKERRQ(ierr);} 4104 if (hasPrec) {ierr = DMPrintCellMatrix(cell, nameP, totDim, totDim, &elemMatP[(c-cStart)*totDim*totDim]);CHKERRQ(ierr);} 4105 } 4106 if (assembleJac) {ierr = DMPlexMatSetClosure(dm, section, globalSection, Jac, cell, &elemMat[(c-cStart)*totDim*totDim], ADD_VALUES);CHKERRQ(ierr);} 4107 ierr = DMPlexMatSetClosure(dm, section, globalSection, JP, cell, &elemMat[(c-cStart)*totDim*totDim], ADD_VALUES);CHKERRQ(ierr); 4108 } 4109 CHKMEMQ; 4110 } 4111 /* Cleanup */ 4112 ierr = DMSNESRestoreFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM);CHKERRQ(ierr); 4113 ierr = PetscQuadratureDestroy(&qGeom);CHKERRQ(ierr); 4114 if (hasFV) {ierr = MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_FALSE);CHKERRQ(ierr);} 4115 ierr = DMRestoreWorkArray(dm, Nf, MPIU_BOOL, &isFE);CHKERRQ(ierr); 4116 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); 4117 /* Compute boundary integrals */ 4118 /* ierr = DMPlexComputeBdJacobian_Internal(dm, X, X_t, t, X_tShift, Jac, JacP, ctx);CHKERRQ(ierr); */ 4119 /* Assemble matrix */ 4120 if (assembleJac) {ierr = MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);ierr = MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);} 4121 ierr = MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);ierr = MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 4122 ierr = PetscLogEventEnd(DMPLEX_JacobianFEM,dm,0,0,0);CHKERRQ(ierr); 4123 CHKMEMQ; 4124 PetscFunctionReturn(0); 4125 } 4126 4127 /******** FEM Assembly Function ********/ 4128 4129 static PetscErrorCode DMConvertPlex_Internal(DM dm, DM *plex, PetscBool copy) 4130 { 4131 PetscBool isPlex; 4132 PetscErrorCode ierr; 4133 4134 PetscFunctionBegin; 4135 ierr = PetscObjectTypeCompare((PetscObject) dm, DMPLEX, &isPlex);CHKERRQ(ierr); 4136 if (isPlex) { 4137 *plex = dm; 4138 ierr = PetscObjectReference((PetscObject) dm);CHKERRQ(ierr); 4139 } else { 4140 ierr = PetscObjectQuery((PetscObject) dm, "dm_plex", (PetscObject *) plex);CHKERRQ(ierr); 4141 if (!*plex) { 4142 ierr = DMConvert(dm,DMPLEX,plex);CHKERRQ(ierr); 4143 ierr = PetscObjectCompose((PetscObject) dm, "dm_plex", (PetscObject) *plex);CHKERRQ(ierr); 4144 if (copy) { 4145 const char *comps[] = {"A", "dmAux"}; 4146 PetscObject obj; 4147 PetscInt i; 4148 4149 for (i = 0; i < 2; ++i) { 4150 ierr = PetscObjectQuery((PetscObject) dm, comps[i], &obj);CHKERRQ(ierr); 4151 ierr = PetscObjectCompose((PetscObject) *plex, comps[i], obj);CHKERRQ(ierr); 4152 } 4153 } 4154 } else { 4155 ierr = PetscObjectReference((PetscObject) *plex);CHKERRQ(ierr); 4156 } 4157 } 4158 PetscFunctionReturn(0); 4159 } 4160 4161 /*@ 4162 DMPlexGetGeometryFVM - Return precomputed geometric data 4163 4164 Collective on DM 4165 4166 Input Parameter: 4167 . dm - The DM 4168 4169 Output Parameters: 4170 + facegeom - The values precomputed from face geometry 4171 . cellgeom - The values precomputed from cell geometry 4172 - minRadius - The minimum radius over the mesh of an inscribed sphere in a cell 4173 4174 Level: developer 4175 4176 .seealso: DMPlexTSSetRHSFunctionLocal() 4177 @*/ 4178 PetscErrorCode DMPlexGetGeometryFVM(DM dm, Vec *facegeom, Vec *cellgeom, PetscReal *minRadius) 4179 { 4180 DM plex; 4181 PetscErrorCode ierr; 4182 4183 PetscFunctionBegin; 4184 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 4185 ierr = DMConvertPlex_Internal(dm,&plex,PETSC_TRUE);CHKERRQ(ierr); 4186 ierr = DMPlexGetDataFVM(plex, NULL, cellgeom, facegeom, NULL);CHKERRQ(ierr); 4187 if (minRadius) {ierr = DMPlexGetMinRadius(plex, minRadius);CHKERRQ(ierr);} 4188 ierr = DMDestroy(&plex);CHKERRQ(ierr); 4189 PetscFunctionReturn(0); 4190 } 4191 4192 /*@ 4193 DMPlexGetGradientDM - Return gradient data layout 4194 4195 Collective on DM 4196 4197 Input Parameters: 4198 + dm - The DM 4199 - fv - The PetscFV 4200 4201 Output Parameter: 4202 . dmGrad - The layout for gradient values 4203 4204 Level: developer 4205 4206 .seealso: DMPlexSNESGetGeometryFVM() 4207 @*/ 4208 PetscErrorCode DMPlexGetGradientDM(DM dm, PetscFV fv, DM *dmGrad) 4209 { 4210 DM plex; 4211 PetscBool computeGradients; 4212 PetscErrorCode ierr; 4213 4214 PetscFunctionBegin; 4215 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 4216 PetscValidHeaderSpecific(fv,PETSCFV_CLASSID,2); 4217 PetscValidPointer(dmGrad,3); 4218 ierr = PetscFVGetComputeGradients(fv, &computeGradients);CHKERRQ(ierr); 4219 if (!computeGradients) {*dmGrad = NULL; PetscFunctionReturn(0);} 4220 ierr = DMConvertPlex_Internal(dm,&plex,PETSC_TRUE);CHKERRQ(ierr); 4221 ierr = DMPlexGetDataFVM(plex, fv, NULL, NULL, dmGrad);CHKERRQ(ierr); 4222 ierr = DMDestroy(&plex);CHKERRQ(ierr); 4223 PetscFunctionReturn(0); 4224 } 4225 4226 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) 4227 { 4228 DM_Plex *mesh = (DM_Plex *) dm->data; 4229 DM plex = NULL, plexA = NULL; 4230 DMEnclosureType encAux; 4231 PetscDS prob, probAux = NULL; 4232 PetscSection section, sectionAux = NULL; 4233 Vec locA = NULL; 4234 PetscScalar *u = NULL, *u_t = NULL, *a = NULL, *elemVec = NULL; 4235 PetscInt v; 4236 PetscInt totDim, totDimAux = 0; 4237 PetscErrorCode ierr; 4238 4239 PetscFunctionBegin; 4240 ierr = DMConvert(dm, DMPLEX, &plex);CHKERRQ(ierr); 4241 ierr = DMGetLocalSection(dm, §ion);CHKERRQ(ierr); 4242 ierr = DMGetDS(dm, &prob);CHKERRQ(ierr); 4243 ierr = PetscDSGetTotalDimension(prob, &totDim);CHKERRQ(ierr); 4244 ierr = PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &locA);CHKERRQ(ierr); 4245 if (locA) { 4246 DM dmAux; 4247 4248 ierr = VecGetDM(locA, &dmAux);CHKERRQ(ierr); 4249 ierr = DMGetEnclosureRelation(dmAux, dm, &encAux);CHKERRQ(ierr); 4250 ierr = DMConvert(dmAux, DMPLEX, &plexA);CHKERRQ(ierr); 4251 ierr = DMGetDS(plexA, &probAux);CHKERRQ(ierr); 4252 ierr = PetscDSGetTotalDimension(probAux, &totDimAux);CHKERRQ(ierr); 4253 ierr = DMGetLocalSection(plexA, §ionAux);CHKERRQ(ierr); 4254 } 4255 for (v = 0; v < numValues; ++v) { 4256 PetscFEGeom *fgeom; 4257 PetscInt maxDegree; 4258 PetscQuadrature qGeom = NULL; 4259 IS pointIS; 4260 const PetscInt *points; 4261 PetscInt numFaces, face, Nq; 4262 4263 ierr = DMLabelGetStratumIS(label, values[v], &pointIS);CHKERRQ(ierr); 4264 if (!pointIS) continue; /* No points with that id on this process */ 4265 { 4266 IS isectIS; 4267 4268 /* TODO: Special cases of ISIntersect where it is quick to check a priori if one is a superset of the other */ 4269 ierr = ISIntersect_Caching_Internal(facetIS,pointIS,&isectIS);CHKERRQ(ierr); 4270 ierr = ISDestroy(&pointIS);CHKERRQ(ierr); 4271 pointIS = isectIS; 4272 } 4273 ierr = ISGetLocalSize(pointIS,&numFaces);CHKERRQ(ierr); 4274 ierr = ISGetIndices(pointIS,&points);CHKERRQ(ierr); 4275 ierr = PetscMalloc4(numFaces*totDim, &u, locX_t ? numFaces*totDim : 0, &u_t, numFaces*totDim, &elemVec, locA ? numFaces*totDimAux : 0, &a);CHKERRQ(ierr); 4276 ierr = DMFieldGetDegree(coordField,pointIS,NULL,&maxDegree);CHKERRQ(ierr); 4277 if (maxDegree <= 1) { 4278 ierr = DMFieldCreateDefaultQuadrature(coordField,pointIS,&qGeom);CHKERRQ(ierr); 4279 } 4280 if (!qGeom) { 4281 PetscFE fe; 4282 4283 ierr = PetscDSGetDiscretization(prob, field, (PetscObject *) &fe);CHKERRQ(ierr); 4284 ierr = PetscFEGetFaceQuadrature(fe, &qGeom);CHKERRQ(ierr); 4285 ierr = PetscObjectReference((PetscObject)qGeom);CHKERRQ(ierr); 4286 } 4287 ierr = PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL);CHKERRQ(ierr); 4288 ierr = DMSNESGetFEGeom(coordField,pointIS,qGeom,PETSC_TRUE,&fgeom);CHKERRQ(ierr); 4289 for (face = 0; face < numFaces; ++face) { 4290 const PetscInt point = points[face], *support, *cone; 4291 PetscScalar *x = NULL; 4292 PetscInt i, coneSize, faceLoc; 4293 4294 ierr = DMPlexGetSupport(dm, point, &support);CHKERRQ(ierr); 4295 ierr = DMPlexGetConeSize(dm, support[0], &coneSize);CHKERRQ(ierr); 4296 ierr = DMPlexGetCone(dm, support[0], &cone);CHKERRQ(ierr); 4297 for (faceLoc = 0; faceLoc < coneSize; ++faceLoc) if (cone[faceLoc] == point) break; 4298 if (faceLoc == coneSize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %D in cone of support[0] %D", point, support[0]); 4299 fgeom->face[face][0] = faceLoc; 4300 ierr = DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x);CHKERRQ(ierr); 4301 for (i = 0; i < totDim; ++i) u[face*totDim+i] = x[i]; 4302 ierr = DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x);CHKERRQ(ierr); 4303 if (locX_t) { 4304 ierr = DMPlexVecGetClosure(plex, section, locX_t, support[0], NULL, &x);CHKERRQ(ierr); 4305 for (i = 0; i < totDim; ++i) u_t[face*totDim+i] = x[i]; 4306 ierr = DMPlexVecRestoreClosure(plex, section, locX_t, support[0], NULL, &x);CHKERRQ(ierr); 4307 } 4308 if (locA) { 4309 PetscInt subp; 4310 4311 ierr = DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp);CHKERRQ(ierr); 4312 ierr = DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x);CHKERRQ(ierr); 4313 for (i = 0; i < totDimAux; ++i) a[face*totDimAux+i] = x[i]; 4314 ierr = DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x);CHKERRQ(ierr); 4315 } 4316 } 4317 ierr = PetscArrayzero(elemVec, numFaces*totDim);CHKERRQ(ierr); 4318 { 4319 PetscFE fe; 4320 PetscInt Nb; 4321 PetscFEGeom *chunkGeom = NULL; 4322 /* Conforming batches */ 4323 PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize; 4324 /* Remainder */ 4325 PetscInt Nr, offset; 4326 4327 ierr = PetscDSGetDiscretization(prob, field, (PetscObject *) &fe);CHKERRQ(ierr); 4328 ierr = PetscFEGetDimension(fe, &Nb);CHKERRQ(ierr); 4329 ierr = PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);CHKERRQ(ierr); 4330 /* TODO: documentation is unclear about what is going on with these numbers: how should Nb / Nq factor in ? */ 4331 blockSize = Nb; 4332 batchSize = numBlocks * blockSize; 4333 ierr = PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);CHKERRQ(ierr); 4334 numChunks = numFaces / (numBatches*batchSize); 4335 Ne = numChunks*numBatches*batchSize; 4336 Nr = numFaces % (numBatches*batchSize); 4337 offset = numFaces - Nr; 4338 ierr = PetscFEGeomGetChunk(fgeom,0,offset,&chunkGeom);CHKERRQ(ierr); 4339 ierr = PetscFEIntegrateBdResidual(prob, field, Ne, chunkGeom, u, u_t, probAux, a, t, elemVec);CHKERRQ(ierr); 4340 ierr = PetscFEGeomRestoreChunk(fgeom, 0, offset, &chunkGeom);CHKERRQ(ierr); 4341 ierr = PetscFEGeomGetChunk(fgeom,offset,numFaces,&chunkGeom);CHKERRQ(ierr); 4342 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); 4343 ierr = PetscFEGeomRestoreChunk(fgeom,offset,numFaces,&chunkGeom);CHKERRQ(ierr); 4344 } 4345 for (face = 0; face < numFaces; ++face) { 4346 const PetscInt point = points[face], *support; 4347 4348 if (mesh->printFEM > 1) {ierr = DMPrintCellVector(point, "BdResidual", totDim, &elemVec[face*totDim]);CHKERRQ(ierr);} 4349 ierr = DMPlexGetSupport(plex, point, &support);CHKERRQ(ierr); 4350 ierr = DMPlexVecSetClosure(plex, NULL, locF, support[0], &elemVec[face*totDim], ADD_ALL_VALUES);CHKERRQ(ierr); 4351 } 4352 ierr = DMSNESRestoreFEGeom(coordField,pointIS,qGeom,PETSC_TRUE,&fgeom);CHKERRQ(ierr); 4353 ierr = PetscQuadratureDestroy(&qGeom);CHKERRQ(ierr); 4354 ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr); 4355 ierr = ISDestroy(&pointIS);CHKERRQ(ierr); 4356 ierr = PetscFree4(u, u_t, elemVec, a);CHKERRQ(ierr); 4357 } 4358 ierr = DMDestroy(&plex);CHKERRQ(ierr); 4359 ierr = DMDestroy(&plexA);CHKERRQ(ierr); 4360 PetscFunctionReturn(0); 4361 } 4362 4363 PetscErrorCode DMPlexComputeBdResidualSingle(DM dm, PetscReal t, DMLabel label, PetscInt numValues, const PetscInt values[], PetscInt field, Vec locX, Vec locX_t, Vec locF) 4364 { 4365 DMField coordField; 4366 DMLabel depthLabel; 4367 IS facetIS; 4368 PetscInt dim; 4369 PetscErrorCode ierr; 4370 4371 PetscFunctionBegin; 4372 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 4373 ierr = DMPlexGetDepthLabel(dm, &depthLabel);CHKERRQ(ierr); 4374 ierr = DMLabelGetStratumIS(depthLabel, dim-1, &facetIS);CHKERRQ(ierr); 4375 ierr = DMGetCoordinateField(dm, &coordField);CHKERRQ(ierr); 4376 ierr = DMPlexComputeBdResidual_Single_Internal(dm, t, label, numValues, values, field, locX, locX_t, locF, coordField, facetIS);CHKERRQ(ierr); 4377 ierr = ISDestroy(&facetIS);CHKERRQ(ierr); 4378 PetscFunctionReturn(0); 4379 } 4380 4381 PetscErrorCode DMPlexComputeBdResidual_Internal(DM dm, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user) 4382 { 4383 PetscDS prob; 4384 PetscInt numBd, bd; 4385 DMField coordField = NULL; 4386 IS facetIS = NULL; 4387 DMLabel depthLabel; 4388 PetscInt dim; 4389 PetscErrorCode ierr; 4390 4391 PetscFunctionBegin; 4392 ierr = DMGetDS(dm, &prob);CHKERRQ(ierr); 4393 ierr = DMPlexGetDepthLabel(dm, &depthLabel);CHKERRQ(ierr); 4394 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 4395 ierr = DMLabelGetStratumIS(depthLabel,dim - 1,&facetIS);CHKERRQ(ierr); 4396 ierr = PetscDSGetNumBoundary(prob, &numBd);CHKERRQ(ierr); 4397 for (bd = 0; bd < numBd; ++bd) { 4398 DMBoundaryConditionType type; 4399 const char *bdLabel; 4400 DMLabel label; 4401 const PetscInt *values; 4402 PetscInt field, numValues; 4403 PetscObject obj; 4404 PetscClassId id; 4405 4406 ierr = PetscDSGetBoundary(prob, bd, &type, NULL, &bdLabel, &field, NULL, NULL, NULL, NULL, &numValues, &values, NULL);CHKERRQ(ierr); 4407 ierr = PetscDSGetDiscretization(prob, field, &obj);CHKERRQ(ierr); 4408 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 4409 if ((id != PETSCFE_CLASSID) || (type & DM_BC_ESSENTIAL)) continue; 4410 if (!facetIS) { 4411 DMLabel depthLabel; 4412 PetscInt dim; 4413 4414 ierr = DMPlexGetDepthLabel(dm, &depthLabel);CHKERRQ(ierr); 4415 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 4416 ierr = DMLabelGetStratumIS(depthLabel, dim - 1, &facetIS);CHKERRQ(ierr); 4417 } 4418 ierr = DMGetCoordinateField(dm, &coordField);CHKERRQ(ierr); 4419 ierr = DMGetLabel(dm, bdLabel, &label);CHKERRQ(ierr); 4420 ierr = DMPlexComputeBdResidual_Single_Internal(dm, t, label, numValues, values, field, locX, locX_t, locF, coordField, facetIS);CHKERRQ(ierr); 4421 } 4422 ierr = ISDestroy(&facetIS);CHKERRQ(ierr); 4423 PetscFunctionReturn(0); 4424 } 4425 4426 PetscErrorCode DMPlexComputeResidual_Internal(DM dm, IS cellIS, PetscReal time, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user) 4427 { 4428 DM_Plex *mesh = (DM_Plex *) dm->data; 4429 const char *name = "Residual"; 4430 DM dmAux = NULL; 4431 DM dmGrad = NULL; 4432 DMLabel ghostLabel = NULL; 4433 PetscDS prob = NULL; 4434 PetscDS probAux = NULL; 4435 PetscSection section = NULL; 4436 PetscBool useFEM = PETSC_FALSE; 4437 PetscBool useFVM = PETSC_FALSE; 4438 PetscBool isImplicit = (locX_t || time == PETSC_MIN_REAL) ? PETSC_TRUE : PETSC_FALSE; 4439 PetscFV fvm = NULL; 4440 PetscFVCellGeom *cgeomFVM = NULL; 4441 PetscFVFaceGeom *fgeomFVM = NULL; 4442 DMField coordField = NULL; 4443 Vec locA, cellGeometryFVM = NULL, faceGeometryFVM = NULL, grad, locGrad = NULL; 4444 PetscScalar *u = NULL, *u_t, *a, *uL, *uR; 4445 IS chunkIS; 4446 const PetscInt *cells; 4447 PetscInt cStart, cEnd, numCells; 4448 PetscInt Nf, f, totDim, totDimAux, numChunks, cellChunkSize, faceChunkSize, chunk, fStart, fEnd; 4449 PetscInt maxDegree = PETSC_MAX_INT; 4450 PetscQuadrature affineQuad = NULL, *quads = NULL; 4451 PetscFEGeom *affineGeom = NULL, **geoms = NULL; 4452 PetscErrorCode ierr; 4453 4454 PetscFunctionBegin; 4455 ierr = PetscLogEventBegin(DMPLEX_ResidualFEM,dm,0,0,0);CHKERRQ(ierr); 4456 /* TODO The places where we have to use isFE are probably the member functions for the PetscDisc class */ 4457 /* TODO The FVM geometry is over-manipulated. Make the precalc functions return exactly what we need */ 4458 /* FEM+FVM */ 4459 ierr = ISGetPointRange(cellIS, &cStart, &cEnd, &cells);CHKERRQ(ierr); 4460 ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr); 4461 /* 1: Get sizes from dm and dmAux */ 4462 ierr = DMGetLocalSection(dm, §ion);CHKERRQ(ierr); 4463 ierr = DMGetLabel(dm, "ghost", &ghostLabel);CHKERRQ(ierr); 4464 ierr = DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob);CHKERRQ(ierr); 4465 ierr = PetscDSGetNumFields(prob, &Nf);CHKERRQ(ierr); 4466 ierr = PetscDSGetTotalDimension(prob, &totDim);CHKERRQ(ierr); 4467 ierr = PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &locA);CHKERRQ(ierr); 4468 if (locA) { 4469 PetscInt subcell; 4470 ierr = VecGetDM(locA, &dmAux);CHKERRQ(ierr); 4471 ierr = DMGetEnclosurePoint(dmAux, dm, DM_ENC_UNKNOWN, cStart, &subcell);CHKERRQ(ierr); 4472 ierr = DMGetCellDS(dmAux, subcell, &probAux);CHKERRQ(ierr); 4473 ierr = PetscDSGetTotalDimension(probAux, &totDimAux);CHKERRQ(ierr); 4474 } 4475 /* 2: Get geometric data */ 4476 for (f = 0; f < Nf; ++f) { 4477 PetscObject obj; 4478 PetscClassId id; 4479 PetscBool fimp; 4480 4481 ierr = PetscDSGetImplicit(prob, f, &fimp);CHKERRQ(ierr); 4482 if (isImplicit != fimp) continue; 4483 ierr = PetscDSGetDiscretization(prob, f, &obj);CHKERRQ(ierr); 4484 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 4485 if (id == PETSCFE_CLASSID) {useFEM = PETSC_TRUE;} 4486 if (id == PETSCFV_CLASSID) {useFVM = PETSC_TRUE; fvm = (PetscFV) obj;} 4487 } 4488 if (useFEM) { 4489 ierr = DMGetCoordinateField(dm, &coordField);CHKERRQ(ierr); 4490 ierr = DMFieldGetDegree(coordField,cellIS,NULL,&maxDegree);CHKERRQ(ierr); 4491 if (maxDegree <= 1) { 4492 ierr = DMFieldCreateDefaultQuadrature(coordField,cellIS,&affineQuad);CHKERRQ(ierr); 4493 if (affineQuad) { 4494 ierr = DMSNESGetFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom);CHKERRQ(ierr); 4495 } 4496 } else { 4497 ierr = PetscCalloc2(Nf,&quads,Nf,&geoms);CHKERRQ(ierr); 4498 for (f = 0; f < Nf; ++f) { 4499 PetscObject obj; 4500 PetscClassId id; 4501 PetscBool fimp; 4502 4503 ierr = PetscDSGetImplicit(prob, f, &fimp);CHKERRQ(ierr); 4504 if (isImplicit != fimp) continue; 4505 ierr = PetscDSGetDiscretization(prob, f, &obj);CHKERRQ(ierr); 4506 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 4507 if (id == PETSCFE_CLASSID) { 4508 PetscFE fe = (PetscFE) obj; 4509 4510 ierr = PetscFEGetQuadrature(fe, &quads[f]);CHKERRQ(ierr); 4511 ierr = PetscObjectReference((PetscObject)quads[f]);CHKERRQ(ierr); 4512 ierr = DMSNESGetFEGeom(coordField,cellIS,quads[f],PETSC_FALSE,&geoms[f]);CHKERRQ(ierr); 4513 } 4514 } 4515 } 4516 } 4517 if (useFVM) { 4518 ierr = DMPlexGetGeometryFVM(dm, &faceGeometryFVM, &cellGeometryFVM, NULL);CHKERRQ(ierr); 4519 ierr = VecGetArrayRead(faceGeometryFVM, (const PetscScalar **) &fgeomFVM);CHKERRQ(ierr); 4520 ierr = VecGetArrayRead(cellGeometryFVM, (const PetscScalar **) &cgeomFVM);CHKERRQ(ierr); 4521 /* Reconstruct and limit cell gradients */ 4522 ierr = DMPlexGetGradientDM(dm, fvm, &dmGrad);CHKERRQ(ierr); 4523 if (dmGrad) { 4524 ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr); 4525 ierr = DMGetGlobalVector(dmGrad, &grad);CHKERRQ(ierr); 4526 ierr = DMPlexReconstructGradients_Internal(dm, fvm, fStart, fEnd, faceGeometryFVM, cellGeometryFVM, locX, grad);CHKERRQ(ierr); 4527 /* Communicate gradient values */ 4528 ierr = DMGetLocalVector(dmGrad, &locGrad);CHKERRQ(ierr); 4529 ierr = DMGlobalToLocalBegin(dmGrad, grad, INSERT_VALUES, locGrad);CHKERRQ(ierr); 4530 ierr = DMGlobalToLocalEnd(dmGrad, grad, INSERT_VALUES, locGrad);CHKERRQ(ierr); 4531 ierr = DMRestoreGlobalVector(dmGrad, &grad);CHKERRQ(ierr); 4532 } 4533 /* Handle non-essential (e.g. outflow) boundary values */ 4534 ierr = DMPlexInsertBoundaryValues(dm, PETSC_FALSE, locX, time, faceGeometryFVM, cellGeometryFVM, locGrad);CHKERRQ(ierr); 4535 } 4536 /* Loop over chunks */ 4537 if (useFEM) {ierr = ISCreate(PETSC_COMM_SELF, &chunkIS);CHKERRQ(ierr);} 4538 numCells = cEnd - cStart; 4539 numChunks = 1; 4540 cellChunkSize = numCells/numChunks; 4541 faceChunkSize = (fEnd - fStart)/numChunks; 4542 numChunks = PetscMin(1,numCells); 4543 for (chunk = 0; chunk < numChunks; ++chunk) { 4544 PetscScalar *elemVec, *fluxL, *fluxR; 4545 PetscReal *vol; 4546 PetscFVFaceGeom *fgeom; 4547 PetscInt cS = cStart+chunk*cellChunkSize, cE = PetscMin(cS+cellChunkSize, cEnd), numCells = cE - cS, c; 4548 PetscInt fS = fStart+chunk*faceChunkSize, fE = PetscMin(fS+faceChunkSize, fEnd), numFaces = 0, face; 4549 4550 /* Extract field coefficients */ 4551 if (useFEM) { 4552 ierr = ISGetPointSubrange(chunkIS, cS, cE, cells);CHKERRQ(ierr); 4553 ierr = DMPlexGetCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a);CHKERRQ(ierr); 4554 ierr = DMGetWorkArray(dm, numCells*totDim, MPIU_SCALAR, &elemVec);CHKERRQ(ierr); 4555 ierr = PetscArrayzero(elemVec, numCells*totDim);CHKERRQ(ierr); 4556 } 4557 if (useFVM) { 4558 ierr = DMPlexGetFaceFields(dm, fS, fE, locX, locX_t, faceGeometryFVM, cellGeometryFVM, locGrad, &numFaces, &uL, &uR);CHKERRQ(ierr); 4559 ierr = DMPlexGetFaceGeometry(dm, fS, fE, faceGeometryFVM, cellGeometryFVM, &numFaces, &fgeom, &vol);CHKERRQ(ierr); 4560 ierr = DMGetWorkArray(dm, numFaces*totDim, MPIU_SCALAR, &fluxL);CHKERRQ(ierr); 4561 ierr = DMGetWorkArray(dm, numFaces*totDim, MPIU_SCALAR, &fluxR);CHKERRQ(ierr); 4562 ierr = PetscArrayzero(fluxL, numFaces*totDim);CHKERRQ(ierr); 4563 ierr = PetscArrayzero(fluxR, numFaces*totDim);CHKERRQ(ierr); 4564 } 4565 /* TODO We will interlace both our field coefficients (u, u_t, uL, uR, etc.) and our output (elemVec, fL, fR). I think this works */ 4566 /* Loop over fields */ 4567 for (f = 0; f < Nf; ++f) { 4568 PetscObject obj; 4569 PetscClassId id; 4570 PetscBool fimp; 4571 PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset; 4572 4573 ierr = PetscDSGetImplicit(prob, f, &fimp);CHKERRQ(ierr); 4574 if (isImplicit != fimp) continue; 4575 ierr = PetscDSGetDiscretization(prob, f, &obj);CHKERRQ(ierr); 4576 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 4577 if (id == PETSCFE_CLASSID) { 4578 PetscFE fe = (PetscFE) obj; 4579 PetscFEGeom *geom = affineGeom ? affineGeom : geoms[f]; 4580 PetscFEGeom *chunkGeom = NULL; 4581 PetscQuadrature quad = affineQuad ? affineQuad : quads[f]; 4582 PetscInt Nq, Nb; 4583 4584 ierr = PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);CHKERRQ(ierr); 4585 ierr = PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL);CHKERRQ(ierr); 4586 ierr = PetscFEGetDimension(fe, &Nb);CHKERRQ(ierr); 4587 blockSize = Nb; 4588 batchSize = numBlocks * blockSize; 4589 ierr = PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);CHKERRQ(ierr); 4590 numChunks = numCells / (numBatches*batchSize); 4591 Ne = numChunks*numBatches*batchSize; 4592 Nr = numCells % (numBatches*batchSize); 4593 offset = numCells - Nr; 4594 /* Integrate FE residual to get elemVec (need fields at quadrature points) */ 4595 /* 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) */ 4596 ierr = PetscFEGeomGetChunk(geom,0,offset,&chunkGeom);CHKERRQ(ierr); 4597 ierr = PetscFEIntegrateResidual(prob, f, Ne, chunkGeom, u, u_t, probAux, a, t, elemVec);CHKERRQ(ierr); 4598 ierr = PetscFEGeomGetChunk(geom,offset,numCells,&chunkGeom);CHKERRQ(ierr); 4599 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); 4600 ierr = PetscFEGeomRestoreChunk(geom,offset,numCells,&chunkGeom);CHKERRQ(ierr); 4601 } else if (id == PETSCFV_CLASSID) { 4602 PetscFV fv = (PetscFV) obj; 4603 4604 Ne = numFaces; 4605 /* Riemann solve over faces (need fields at face centroids) */ 4606 /* We need to evaluate FE fields at those coordinates */ 4607 ierr = PetscFVIntegrateRHSFunction(fv, prob, f, Ne, fgeom, vol, uL, uR, fluxL, fluxR);CHKERRQ(ierr); 4608 } else SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", f); 4609 } 4610 /* Loop over domain */ 4611 if (useFEM) { 4612 /* Add elemVec to locX */ 4613 for (c = cS; c < cE; ++c) { 4614 const PetscInt cell = cells ? cells[c] : c; 4615 const PetscInt cind = c - cStart; 4616 4617 if (mesh->printFEM > 1) {ierr = DMPrintCellVector(cell, name, totDim, &elemVec[cind*totDim]);CHKERRQ(ierr);} 4618 if (ghostLabel) { 4619 PetscInt ghostVal; 4620 4621 ierr = DMLabelGetValue(ghostLabel,cell,&ghostVal);CHKERRQ(ierr); 4622 if (ghostVal > 0) continue; 4623 } 4624 ierr = DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind*totDim], ADD_ALL_VALUES);CHKERRQ(ierr); 4625 } 4626 } 4627 if (useFVM) { 4628 PetscScalar *fa; 4629 PetscInt iface; 4630 4631 ierr = VecGetArray(locF, &fa);CHKERRQ(ierr); 4632 for (f = 0; f < Nf; ++f) { 4633 PetscFV fv; 4634 PetscObject obj; 4635 PetscClassId id; 4636 PetscInt foff, pdim; 4637 4638 ierr = PetscDSGetDiscretization(prob, f, &obj);CHKERRQ(ierr); 4639 ierr = PetscDSGetFieldOffset(prob, f, &foff);CHKERRQ(ierr); 4640 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 4641 if (id != PETSCFV_CLASSID) continue; 4642 fv = (PetscFV) obj; 4643 ierr = PetscFVGetNumComponents(fv, &pdim);CHKERRQ(ierr); 4644 /* Accumulate fluxes to cells */ 4645 for (face = fS, iface = 0; face < fE; ++face) { 4646 const PetscInt *scells; 4647 PetscScalar *fL = NULL, *fR = NULL; 4648 PetscInt ghost, d, nsupp, nchild; 4649 4650 ierr = DMLabelGetValue(ghostLabel, face, &ghost);CHKERRQ(ierr); 4651 ierr = DMPlexGetSupportSize(dm, face, &nsupp);CHKERRQ(ierr); 4652 ierr = DMPlexGetTreeChildren(dm, face, &nchild, NULL);CHKERRQ(ierr); 4653 if (ghost >= 0 || nsupp > 2 || nchild > 0) continue; 4654 ierr = DMPlexGetSupport(dm, face, &scells);CHKERRQ(ierr); 4655 ierr = DMLabelGetValue(ghostLabel,scells[0],&ghost);CHKERRQ(ierr); 4656 if (ghost <= 0) {ierr = DMPlexPointLocalFieldRef(dm, scells[0], f, fa, &fL);CHKERRQ(ierr);} 4657 ierr = DMLabelGetValue(ghostLabel,scells[1],&ghost);CHKERRQ(ierr); 4658 if (ghost <= 0) {ierr = DMPlexPointLocalFieldRef(dm, scells[1], f, fa, &fR);CHKERRQ(ierr);} 4659 for (d = 0; d < pdim; ++d) { 4660 if (fL) fL[d] -= fluxL[iface*totDim+foff+d]; 4661 if (fR) fR[d] += fluxR[iface*totDim+foff+d]; 4662 } 4663 ++iface; 4664 } 4665 } 4666 ierr = VecRestoreArray(locF, &fa);CHKERRQ(ierr); 4667 } 4668 /* Handle time derivative */ 4669 if (locX_t) { 4670 PetscScalar *x_t, *fa; 4671 4672 ierr = VecGetArray(locF, &fa);CHKERRQ(ierr); 4673 ierr = VecGetArray(locX_t, &x_t);CHKERRQ(ierr); 4674 for (f = 0; f < Nf; ++f) { 4675 PetscFV fv; 4676 PetscObject obj; 4677 PetscClassId id; 4678 PetscInt pdim, d; 4679 4680 ierr = PetscDSGetDiscretization(prob, f, &obj);CHKERRQ(ierr); 4681 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 4682 if (id != PETSCFV_CLASSID) continue; 4683 fv = (PetscFV) obj; 4684 ierr = PetscFVGetNumComponents(fv, &pdim);CHKERRQ(ierr); 4685 for (c = cS; c < cE; ++c) { 4686 const PetscInt cell = cells ? cells[c] : c; 4687 PetscScalar *u_t, *r; 4688 4689 if (ghostLabel) { 4690 PetscInt ghostVal; 4691 4692 ierr = DMLabelGetValue(ghostLabel, cell, &ghostVal);CHKERRQ(ierr); 4693 if (ghostVal > 0) continue; 4694 } 4695 ierr = DMPlexPointLocalFieldRead(dm, cell, f, x_t, &u_t);CHKERRQ(ierr); 4696 ierr = DMPlexPointLocalFieldRef(dm, cell, f, fa, &r);CHKERRQ(ierr); 4697 for (d = 0; d < pdim; ++d) r[d] += u_t[d]; 4698 } 4699 } 4700 ierr = VecRestoreArray(locX_t, &x_t);CHKERRQ(ierr); 4701 ierr = VecRestoreArray(locF, &fa);CHKERRQ(ierr); 4702 } 4703 if (useFEM) { 4704 ierr = DMPlexRestoreCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a);CHKERRQ(ierr); 4705 ierr = DMRestoreWorkArray(dm, numCells*totDim, MPIU_SCALAR, &elemVec);CHKERRQ(ierr); 4706 } 4707 if (useFVM) { 4708 ierr = DMPlexRestoreFaceFields(dm, fS, fE, locX, locX_t, faceGeometryFVM, cellGeometryFVM, locGrad, &numFaces, &uL, &uR);CHKERRQ(ierr); 4709 ierr = DMPlexRestoreFaceGeometry(dm, fS, fE, faceGeometryFVM, cellGeometryFVM, &numFaces, &fgeom, &vol);CHKERRQ(ierr); 4710 ierr = DMRestoreWorkArray(dm, numFaces*totDim, MPIU_SCALAR, &fluxL);CHKERRQ(ierr); 4711 ierr = DMRestoreWorkArray(dm, numFaces*totDim, MPIU_SCALAR, &fluxR);CHKERRQ(ierr); 4712 if (dmGrad) {ierr = DMRestoreLocalVector(dmGrad, &locGrad);CHKERRQ(ierr);} 4713 } 4714 } 4715 if (useFEM) {ierr = ISDestroy(&chunkIS);CHKERRQ(ierr);} 4716 ierr = ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);CHKERRQ(ierr); 4717 4718 if (useFEM) { 4719 ierr = DMPlexComputeBdResidual_Internal(dm, locX, locX_t, t, locF, user);CHKERRQ(ierr); 4720 4721 if (maxDegree <= 1) { 4722 ierr = DMSNESRestoreFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom);CHKERRQ(ierr); 4723 ierr = PetscQuadratureDestroy(&affineQuad);CHKERRQ(ierr); 4724 } else { 4725 for (f = 0; f < Nf; ++f) { 4726 ierr = DMSNESRestoreFEGeom(coordField,cellIS,quads[f],PETSC_FALSE,&geoms[f]);CHKERRQ(ierr); 4727 ierr = PetscQuadratureDestroy(&quads[f]);CHKERRQ(ierr); 4728 } 4729 ierr = PetscFree2(quads,geoms);CHKERRQ(ierr); 4730 } 4731 } 4732 4733 /* FEM */ 4734 /* 1: Get sizes from dm and dmAux */ 4735 /* 2: Get geometric data */ 4736 /* 3: Handle boundary values */ 4737 /* 4: Loop over domain */ 4738 /* Extract coefficients */ 4739 /* Loop over fields */ 4740 /* Set tiling for FE*/ 4741 /* Integrate FE residual to get elemVec */ 4742 /* Loop over subdomain */ 4743 /* Loop over quad points */ 4744 /* Transform coords to real space */ 4745 /* Evaluate field and aux fields at point */ 4746 /* Evaluate residual at point */ 4747 /* Transform residual to real space */ 4748 /* Add residual to elemVec */ 4749 /* Loop over domain */ 4750 /* Add elemVec to locX */ 4751 4752 /* FVM */ 4753 /* Get geometric data */ 4754 /* If using gradients */ 4755 /* Compute gradient data */ 4756 /* Loop over domain faces */ 4757 /* Count computational faces */ 4758 /* Reconstruct cell gradient */ 4759 /* Loop over domain cells */ 4760 /* Limit cell gradients */ 4761 /* Handle boundary values */ 4762 /* Loop over domain faces */ 4763 /* Read out field, centroid, normal, volume for each side of face */ 4764 /* Riemann solve over faces */ 4765 /* Loop over domain faces */ 4766 /* Accumulate fluxes to cells */ 4767 /* TODO Change printFEM to printDisc here */ 4768 if (mesh->printFEM) { 4769 Vec locFbc; 4770 PetscInt pStart, pEnd, p, maxDof; 4771 PetscScalar *zeroes; 4772 4773 ierr = VecDuplicate(locF,&locFbc);CHKERRQ(ierr); 4774 ierr = VecCopy(locF,locFbc);CHKERRQ(ierr); 4775 ierr = PetscSectionGetChart(section,&pStart,&pEnd);CHKERRQ(ierr); 4776 ierr = PetscSectionGetMaxDof(section,&maxDof);CHKERRQ(ierr); 4777 ierr = PetscCalloc1(maxDof,&zeroes);CHKERRQ(ierr); 4778 for (p = pStart; p < pEnd; p++) { 4779 ierr = VecSetValuesSection(locFbc,section,p,zeroes,INSERT_BC_VALUES);CHKERRQ(ierr); 4780 } 4781 ierr = PetscFree(zeroes);CHKERRQ(ierr); 4782 ierr = DMPrintLocalVec(dm, name, mesh->printTol, locFbc);CHKERRQ(ierr); 4783 ierr = VecDestroy(&locFbc);CHKERRQ(ierr); 4784 } 4785 ierr = PetscLogEventEnd(DMPLEX_ResidualFEM,dm,0,0,0);CHKERRQ(ierr); 4786 PetscFunctionReturn(0); 4787 } 4788 4789 PetscErrorCode DMPlexComputeResidual_Hybrid_Internal(DM dm, IS cellIS, PetscReal time, Vec locX, Vec locX_t, PetscReal t, Vec locF, void *user) 4790 { 4791 DM_Plex *mesh = (DM_Plex *) dm->data; 4792 const char *name = "Hybrid Residual"; 4793 DM dmAux = NULL; 4794 DMLabel ghostLabel = NULL; 4795 PetscDS prob = NULL; 4796 PetscDS probAux = NULL; 4797 PetscSection section = NULL; 4798 DMField coordField = NULL; 4799 Vec locA; 4800 PetscScalar *u = NULL, *u_t, *a; 4801 PetscScalar *elemVec; 4802 IS chunkIS; 4803 const PetscInt *cells; 4804 PetscInt *faces; 4805 PetscInt cStart, cEnd, numCells; 4806 PetscInt Nf, f, totDim, totDimAux, numChunks, cellChunkSize, chunk; 4807 PetscInt maxDegree = PETSC_MAX_INT; 4808 PetscQuadrature affineQuad = NULL, *quads = NULL; 4809 PetscFEGeom *affineGeom = NULL, **geoms = NULL; 4810 PetscErrorCode ierr; 4811 4812 PetscFunctionBegin; 4813 ierr = PetscLogEventBegin(DMPLEX_ResidualFEM,dm,0,0,0);CHKERRQ(ierr); 4814 /* TODO The places where we have to use isFE are probably the member functions for the PetscDisc class */ 4815 /* FEM */ 4816 ierr = ISGetPointRange(cellIS, &cStart, &cEnd, &cells);CHKERRQ(ierr); 4817 /* 1: Get sizes from dm and dmAux */ 4818 ierr = DMGetSection(dm, §ion);CHKERRQ(ierr); 4819 ierr = DMGetLabel(dm, "ghost", &ghostLabel);CHKERRQ(ierr); 4820 ierr = DMGetCellDS(dm, cStart, &prob);CHKERRQ(ierr); 4821 ierr = PetscDSGetNumFields(prob, &Nf);CHKERRQ(ierr); 4822 ierr = PetscDSGetTotalDimension(prob, &totDim);CHKERRQ(ierr); 4823 ierr = PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &locA);CHKERRQ(ierr); 4824 if (locA) { 4825 ierr = VecGetDM(locA, &dmAux);CHKERRQ(ierr); 4826 ierr = DMGetCellDS(dmAux, cStart, &probAux);CHKERRQ(ierr); 4827 ierr = PetscDSGetTotalDimension(probAux, &totDimAux);CHKERRQ(ierr); 4828 } 4829 /* 2: Setup geometric data */ 4830 ierr = DMGetCoordinateField(dm, &coordField);CHKERRQ(ierr); 4831 ierr = DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree);CHKERRQ(ierr); 4832 if (maxDegree > 1) { 4833 ierr = PetscCalloc2(Nf,&quads,Nf,&geoms);CHKERRQ(ierr); 4834 for (f = 0; f < Nf; ++f) { 4835 PetscFE fe; 4836 4837 ierr = PetscDSGetDiscretization(prob, f, (PetscObject *) &fe);CHKERRQ(ierr); 4838 if (fe) { 4839 ierr = PetscFEGetQuadrature(fe, &quads[f]);CHKERRQ(ierr); 4840 ierr = PetscObjectReference((PetscObject) quads[f]);CHKERRQ(ierr); 4841 } 4842 } 4843 } 4844 /* Loop over chunks */ 4845 numCells = cEnd - cStart; 4846 cellChunkSize = numCells; 4847 numChunks = !numCells ? 0 : PetscCeilReal(((PetscReal) numCells)/cellChunkSize); 4848 ierr = PetscCalloc1(2*cellChunkSize, &faces);CHKERRQ(ierr); 4849 ierr = ISCreateGeneral(PETSC_COMM_SELF, cellChunkSize, faces, PETSC_USE_POINTER, &chunkIS);CHKERRQ(ierr); 4850 /* Extract field coefficients */ 4851 /* NOTE This needs the end cap faces to have identical orientations */ 4852 ierr = DMPlexGetCellFields(dm, cellIS, locX, locX_t, locA, &u, &u_t, &a);CHKERRQ(ierr); 4853 ierr = DMGetWorkArray(dm, cellChunkSize*totDim, MPIU_SCALAR, &elemVec);CHKERRQ(ierr); 4854 for (chunk = 0; chunk < numChunks; ++chunk) { 4855 PetscInt cS = cStart+chunk*cellChunkSize, cE = PetscMin(cS+cellChunkSize, cEnd), numCells = cE - cS, c; 4856 4857 ierr = PetscMemzero(elemVec, cellChunkSize*totDim * sizeof(PetscScalar));CHKERRQ(ierr); 4858 /* Get faces */ 4859 for (c = cS; c < cE; ++c) { 4860 const PetscInt cell = cells ? cells[c] : c; 4861 const PetscInt *cone; 4862 ierr = DMPlexGetCone(dm, cell, &cone);CHKERRQ(ierr); 4863 faces[(c-cS)*2+0] = cone[0]; 4864 faces[(c-cS)*2+1] = cone[1]; 4865 } 4866 ierr = ISGeneralSetIndices(chunkIS, cellChunkSize, faces, PETSC_USE_POINTER);CHKERRQ(ierr); 4867 /* Get geometric data */ 4868 if (maxDegree <= 1) { 4869 if (!affineQuad) {ierr = DMFieldCreateDefaultQuadrature(coordField, chunkIS, &affineQuad);CHKERRQ(ierr);} 4870 if (affineQuad) {ierr = DMSNESGetFEGeom(coordField, chunkIS, affineQuad, PETSC_TRUE, &affineGeom);CHKERRQ(ierr);} 4871 } else { 4872 for (f = 0; f < Nf; ++f) { 4873 if (quads[f]) {ierr = DMSNESGetFEGeom(coordField, chunkIS, quads[f], PETSC_TRUE, &geoms[f]);CHKERRQ(ierr);} 4874 } 4875 } 4876 /* Loop over fields */ 4877 for (f = 0; f < Nf; ++f) { 4878 PetscFE fe; 4879 PetscFEGeom *geom = affineGeom ? affineGeom : geoms[f]; 4880 PetscFEGeom *chunkGeom = NULL; 4881 PetscQuadrature quad = affineQuad ? affineQuad : quads[f]; 4882 PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset, Nq, Nb; 4883 4884 ierr = PetscDSGetDiscretization(prob, f, (PetscObject *) &fe);CHKERRQ(ierr); 4885 if (!fe) continue; 4886 ierr = PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);CHKERRQ(ierr); 4887 ierr = PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL);CHKERRQ(ierr); 4888 ierr = PetscFEGetDimension(fe, &Nb);CHKERRQ(ierr); 4889 blockSize = Nb; 4890 batchSize = numBlocks * blockSize; 4891 ierr = PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);CHKERRQ(ierr); 4892 numChunks = numCells / (numBatches*batchSize); 4893 Ne = numChunks*numBatches*batchSize; 4894 Nr = numCells % (numBatches*batchSize); 4895 offset = numCells - Nr; 4896 ierr = PetscFEGeomGetChunk(geom,0,offset,&chunkGeom);CHKERRQ(ierr); 4897 ierr = PetscFEIntegrateHybridResidual(prob, f, Ne, chunkGeom, u, u_t, probAux, a, t, elemVec);CHKERRQ(ierr); 4898 ierr = PetscFEGeomGetChunk(geom,offset,numCells,&chunkGeom);CHKERRQ(ierr); 4899 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); 4900 ierr = PetscFEGeomRestoreChunk(geom,offset,numCells,&chunkGeom);CHKERRQ(ierr); 4901 } 4902 /* Add elemVec to locX */ 4903 for (c = cS; c < cE; ++c) { 4904 const PetscInt cell = cells ? cells[c] : c; 4905 const PetscInt cind = c - cStart; 4906 4907 if (mesh->printFEM > 1) {ierr = DMPrintCellVector(cell, name, totDim, &elemVec[cind*totDim]);CHKERRQ(ierr);} 4908 if (ghostLabel) { 4909 PetscInt ghostVal; 4910 4911 ierr = DMLabelGetValue(ghostLabel,cell,&ghostVal);CHKERRQ(ierr); 4912 if (ghostVal > 0) continue; 4913 } 4914 ierr = DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind*totDim], ADD_ALL_VALUES);CHKERRQ(ierr); 4915 } 4916 } 4917 ierr = DMPlexRestoreCellFields(dm, cellIS, locX, locX_t, locA, &u, &u_t, &a);CHKERRQ(ierr); 4918 ierr = DMRestoreWorkArray(dm, numCells*totDim, MPIU_SCALAR, &elemVec);CHKERRQ(ierr); 4919 ierr = PetscFree(faces);CHKERRQ(ierr); 4920 ierr = ISDestroy(&chunkIS);CHKERRQ(ierr); 4921 ierr = ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);CHKERRQ(ierr); 4922 if (maxDegree <= 1) { 4923 ierr = DMSNESRestoreFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom);CHKERRQ(ierr); 4924 ierr = PetscQuadratureDestroy(&affineQuad);CHKERRQ(ierr); 4925 } else { 4926 for (f = 0; f < Nf; ++f) { 4927 if (geoms) {ierr = DMSNESRestoreFEGeom(coordField,cellIS,quads[f],PETSC_FALSE,&geoms[f]);CHKERRQ(ierr);} 4928 if (quads) {ierr = PetscQuadratureDestroy(&quads[f]);CHKERRQ(ierr);} 4929 } 4930 ierr = PetscFree2(quads,geoms);CHKERRQ(ierr); 4931 } 4932 ierr = PetscLogEventEnd(DMPLEX_ResidualFEM,dm,0,0,0);CHKERRQ(ierr); 4933 PetscFunctionReturn(0); 4934 } 4935 4936 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) 4937 { 4938 DM_Plex *mesh = (DM_Plex *) dm->data; 4939 DM plex = NULL, plexA = NULL, tdm; 4940 DMEnclosureType encAux; 4941 PetscDS prob, probAux = NULL; 4942 PetscSection section, sectionAux = NULL; 4943 PetscSection globalSection, subSection = NULL; 4944 Vec locA = NULL, tv; 4945 PetscScalar *u = NULL, *u_t = NULL, *a = NULL, *elemMat = NULL; 4946 PetscInt v; 4947 PetscInt Nf, totDim, totDimAux = 0; 4948 PetscBool isMatISP, transform; 4949 PetscErrorCode ierr; 4950 4951 PetscFunctionBegin; 4952 ierr = DMConvert(dm, DMPLEX, &plex);CHKERRQ(ierr); 4953 ierr = DMHasBasisTransform(dm, &transform);CHKERRQ(ierr); 4954 ierr = DMGetBasisTransformDM_Internal(dm, &tdm);CHKERRQ(ierr); 4955 ierr = DMGetBasisTransformVec_Internal(dm, &tv);CHKERRQ(ierr); 4956 ierr = DMGetLocalSection(dm, §ion);CHKERRQ(ierr); 4957 ierr = DMGetDS(dm, &prob);CHKERRQ(ierr); 4958 ierr = PetscDSGetNumFields(prob, &Nf);CHKERRQ(ierr); 4959 ierr = PetscDSGetTotalDimension(prob, &totDim);CHKERRQ(ierr); 4960 ierr = PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &locA);CHKERRQ(ierr); 4961 if (locA) { 4962 DM dmAux; 4963 4964 ierr = VecGetDM(locA, &dmAux);CHKERRQ(ierr); 4965 ierr = DMGetEnclosureRelation(dmAux, dm, &encAux);CHKERRQ(ierr); 4966 ierr = DMConvert(dmAux, DMPLEX, &plexA);CHKERRQ(ierr); 4967 ierr = DMGetDS(plexA, &probAux);CHKERRQ(ierr); 4968 ierr = PetscDSGetTotalDimension(probAux, &totDimAux);CHKERRQ(ierr); 4969 ierr = DMGetLocalSection(plexA, §ionAux);CHKERRQ(ierr); 4970 } 4971 4972 ierr = PetscObjectTypeCompare((PetscObject) JacP, MATIS, &isMatISP);CHKERRQ(ierr); 4973 ierr = DMGetGlobalSection(dm, &globalSection);CHKERRQ(ierr); 4974 if (isMatISP) {ierr = DMPlexGetSubdomainSection(dm, &subSection);CHKERRQ(ierr);} 4975 for (v = 0; v < numValues; ++v) { 4976 PetscFEGeom *fgeom; 4977 PetscInt maxDegree; 4978 PetscQuadrature qGeom = NULL; 4979 IS pointIS; 4980 const PetscInt *points; 4981 PetscInt numFaces, face, Nq; 4982 4983 ierr = DMLabelGetStratumIS(label, values[v], &pointIS);CHKERRQ(ierr); 4984 if (!pointIS) continue; /* No points with that id on this process */ 4985 { 4986 IS isectIS; 4987 4988 /* TODO: Special cases of ISIntersect where it is quick to check a prior if one is a superset of the other */ 4989 ierr = ISIntersect_Caching_Internal(facetIS,pointIS,&isectIS);CHKERRQ(ierr); 4990 ierr = ISDestroy(&pointIS);CHKERRQ(ierr); 4991 pointIS = isectIS; 4992 } 4993 ierr = ISGetLocalSize(pointIS, &numFaces);CHKERRQ(ierr); 4994 ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr); 4995 ierr = PetscMalloc4(numFaces*totDim, &u, locX_t ? numFaces*totDim : 0, &u_t, numFaces*totDim*totDim, &elemMat, locA ? numFaces*totDimAux : 0, &a);CHKERRQ(ierr); 4996 ierr = DMFieldGetDegree(coordField,pointIS,NULL,&maxDegree);CHKERRQ(ierr); 4997 if (maxDegree <= 1) { 4998 ierr = DMFieldCreateDefaultQuadrature(coordField,pointIS,&qGeom);CHKERRQ(ierr); 4999 } 5000 if (!qGeom) { 5001 PetscFE fe; 5002 5003 ierr = PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fe);CHKERRQ(ierr); 5004 ierr = PetscFEGetFaceQuadrature(fe, &qGeom);CHKERRQ(ierr); 5005 ierr = PetscObjectReference((PetscObject)qGeom);CHKERRQ(ierr); 5006 } 5007 ierr = PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL);CHKERRQ(ierr); 5008 ierr = DMSNESGetFEGeom(coordField,pointIS,qGeom,PETSC_TRUE,&fgeom);CHKERRQ(ierr); 5009 for (face = 0; face < numFaces; ++face) { 5010 const PetscInt point = points[face], *support, *cone; 5011 PetscScalar *x = NULL; 5012 PetscInt i, coneSize, faceLoc; 5013 5014 ierr = DMPlexGetSupport(dm, point, &support);CHKERRQ(ierr); 5015 ierr = DMPlexGetConeSize(dm, support[0], &coneSize);CHKERRQ(ierr); 5016 ierr = DMPlexGetCone(dm, support[0], &cone);CHKERRQ(ierr); 5017 for (faceLoc = 0; faceLoc < coneSize; ++faceLoc) if (cone[faceLoc] == point) break; 5018 if (faceLoc == coneSize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %D in cone of support[0] %D", point, support[0]); 5019 fgeom->face[face][0] = faceLoc; 5020 ierr = DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x);CHKERRQ(ierr); 5021 for (i = 0; i < totDim; ++i) u[face*totDim+i] = x[i]; 5022 ierr = DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x);CHKERRQ(ierr); 5023 if (locX_t) { 5024 ierr = DMPlexVecGetClosure(plex, section, locX_t, support[0], NULL, &x);CHKERRQ(ierr); 5025 for (i = 0; i < totDim; ++i) u_t[face*totDim+i] = x[i]; 5026 ierr = DMPlexVecRestoreClosure(plex, section, locX_t, support[0], NULL, &x);CHKERRQ(ierr); 5027 } 5028 if (locA) { 5029 PetscInt subp; 5030 ierr = DMGetEnclosurePoint(plexA, dm, encAux, support[0], &subp);CHKERRQ(ierr); 5031 ierr = DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x);CHKERRQ(ierr); 5032 for (i = 0; i < totDimAux; ++i) a[face*totDimAux+i] = x[i]; 5033 ierr = DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x);CHKERRQ(ierr); 5034 } 5035 } 5036 ierr = PetscArrayzero(elemMat, numFaces*totDim*totDim);CHKERRQ(ierr); 5037 { 5038 PetscFE fe; 5039 PetscInt Nb; 5040 /* Conforming batches */ 5041 PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize; 5042 /* Remainder */ 5043 PetscFEGeom *chunkGeom = NULL; 5044 PetscInt fieldJ, Nr, offset; 5045 5046 ierr = PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fe);CHKERRQ(ierr); 5047 ierr = PetscFEGetDimension(fe, &Nb);CHKERRQ(ierr); 5048 ierr = PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);CHKERRQ(ierr); 5049 blockSize = Nb; 5050 batchSize = numBlocks * blockSize; 5051 ierr = PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);CHKERRQ(ierr); 5052 numChunks = numFaces / (numBatches*batchSize); 5053 Ne = numChunks*numBatches*batchSize; 5054 Nr = numFaces % (numBatches*batchSize); 5055 offset = numFaces - Nr; 5056 ierr = PetscFEGeomGetChunk(fgeom,0,offset,&chunkGeom);CHKERRQ(ierr); 5057 for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 5058 ierr = PetscFEIntegrateBdJacobian(prob, fieldI, fieldJ, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat);CHKERRQ(ierr); 5059 } 5060 ierr = PetscFEGeomGetChunk(fgeom,offset,numFaces,&chunkGeom);CHKERRQ(ierr); 5061 for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 5062 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); 5063 } 5064 ierr = PetscFEGeomRestoreChunk(fgeom,offset,numFaces,&chunkGeom);CHKERRQ(ierr); 5065 } 5066 for (face = 0; face < numFaces; ++face) { 5067 const PetscInt point = points[face], *support; 5068 5069 /* Transform to global basis before insertion in Jacobian */ 5070 ierr = DMPlexGetSupport(plex, point, &support);CHKERRQ(ierr); 5071 if (transform) {ierr = DMPlexBasisTransformPointTensor_Internal(dm, tdm, tv, support[0], PETSC_TRUE, totDim, &elemMat[face*totDim*totDim]);CHKERRQ(ierr);} 5072 if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(point, "BdJacobian", totDim, totDim, &elemMat[face*totDim*totDim]);CHKERRQ(ierr);} 5073 if (!isMatISP) { 5074 ierr = DMPlexMatSetClosure(plex, section, globalSection, JacP, support[0], &elemMat[face*totDim*totDim], ADD_VALUES);CHKERRQ(ierr); 5075 } else { 5076 Mat lJ; 5077 5078 ierr = MatISGetLocalMat(JacP, &lJ);CHKERRQ(ierr); 5079 ierr = DMPlexMatSetClosure(plex, section, subSection, lJ, support[0], &elemMat[face*totDim*totDim], ADD_VALUES);CHKERRQ(ierr); 5080 } 5081 } 5082 ierr = DMSNESRestoreFEGeom(coordField,pointIS,qGeom,PETSC_TRUE,&fgeom);CHKERRQ(ierr); 5083 ierr = PetscQuadratureDestroy(&qGeom);CHKERRQ(ierr); 5084 ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr); 5085 ierr = ISDestroy(&pointIS);CHKERRQ(ierr); 5086 ierr = PetscFree4(u, u_t, elemMat, a);CHKERRQ(ierr); 5087 } 5088 if (plex) {ierr = DMDestroy(&plex);CHKERRQ(ierr);} 5089 if (plexA) {ierr = DMDestroy(&plexA);CHKERRQ(ierr);} 5090 PetscFunctionReturn(0); 5091 } 5092 5093 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) 5094 { 5095 DMField coordField; 5096 DMLabel depthLabel; 5097 IS facetIS; 5098 PetscInt dim; 5099 PetscErrorCode ierr; 5100 5101 PetscFunctionBegin; 5102 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 5103 ierr = DMPlexGetDepthLabel(dm, &depthLabel);CHKERRQ(ierr); 5104 ierr = DMLabelGetStratumIS(depthLabel, dim-1, &facetIS);CHKERRQ(ierr); 5105 ierr = DMGetCoordinateField(dm, &coordField);CHKERRQ(ierr); 5106 ierr = DMPlexComputeBdJacobian_Single_Internal(dm, t, label, numValues, values, field, locX, locX_t, X_tShift, Jac, JacP, coordField, facetIS);CHKERRQ(ierr); 5107 ierr = ISDestroy(&facetIS);CHKERRQ(ierr); 5108 PetscFunctionReturn(0); 5109 } 5110 5111 PetscErrorCode DMPlexComputeBdJacobian_Internal(DM dm, Vec locX, Vec locX_t, PetscReal t, PetscReal X_tShift, Mat Jac, Mat JacP, void *user) 5112 { 5113 PetscDS prob; 5114 PetscInt dim, numBd, bd; 5115 DMLabel depthLabel; 5116 DMField coordField = NULL; 5117 IS facetIS; 5118 PetscErrorCode ierr; 5119 5120 PetscFunctionBegin; 5121 ierr = DMGetDS(dm, &prob);CHKERRQ(ierr); 5122 ierr = DMPlexGetDepthLabel(dm, &depthLabel);CHKERRQ(ierr); 5123 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 5124 ierr = DMLabelGetStratumIS(depthLabel, dim-1, &facetIS);CHKERRQ(ierr); 5125 ierr = PetscDSGetNumBoundary(prob, &numBd);CHKERRQ(ierr); 5126 ierr = DMGetCoordinateField(dm, &coordField);CHKERRQ(ierr); 5127 for (bd = 0; bd < numBd; ++bd) { 5128 DMBoundaryConditionType type; 5129 const char *bdLabel; 5130 DMLabel label; 5131 const PetscInt *values; 5132 PetscInt fieldI, numValues; 5133 PetscObject obj; 5134 PetscClassId id; 5135 5136 ierr = PetscDSGetBoundary(prob, bd, &type, NULL, &bdLabel, &fieldI, NULL, NULL, NULL, NULL, &numValues, &values, NULL);CHKERRQ(ierr); 5137 ierr = PetscDSGetDiscretization(prob, fieldI, &obj);CHKERRQ(ierr); 5138 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 5139 if ((id != PETSCFE_CLASSID) || (type & DM_BC_ESSENTIAL)) continue; 5140 ierr = DMGetLabel(dm, bdLabel, &label);CHKERRQ(ierr); 5141 ierr = DMPlexComputeBdJacobian_Single_Internal(dm, t, label, numValues, values, fieldI, locX, locX_t, X_tShift, Jac, JacP, coordField, facetIS);CHKERRQ(ierr); 5142 } 5143 ierr = ISDestroy(&facetIS);CHKERRQ(ierr); 5144 PetscFunctionReturn(0); 5145 } 5146 5147 PetscErrorCode DMPlexComputeJacobian_Internal(DM dm, IS cellIS, PetscReal t, PetscReal X_tShift, Vec X, Vec X_t, Mat Jac, Mat JacP,void *user) 5148 { 5149 DM_Plex *mesh = (DM_Plex *) dm->data; 5150 const char *name = "Jacobian"; 5151 DM dmAux, plex, tdm; 5152 DMEnclosureType encAux; 5153 Vec A, tv; 5154 DMField coordField; 5155 PetscDS prob, probAux = NULL; 5156 PetscSection section, globalSection, subSection, sectionAux; 5157 PetscScalar *elemMat, *elemMatP, *elemMatD, *u, *u_t, *a = NULL; 5158 const PetscInt *cells; 5159 PetscInt Nf, fieldI, fieldJ; 5160 PetscInt totDim, totDimAux, cStart, cEnd, numCells, c; 5161 PetscBool isMatIS, isMatISP, hasJac, hasPrec, hasDyn, hasFV = PETSC_FALSE, transform; 5162 PetscErrorCode ierr; 5163 5164 PetscFunctionBegin; 5165 ierr = PetscLogEventBegin(DMPLEX_JacobianFEM,dm,0,0,0);CHKERRQ(ierr); 5166 ierr = ISGetLocalSize(cellIS, &numCells);CHKERRQ(ierr); 5167 ierr = ISGetPointRange(cellIS, &cStart, &cEnd, &cells);CHKERRQ(ierr); 5168 ierr = DMHasBasisTransform(dm, &transform);CHKERRQ(ierr); 5169 ierr = DMGetBasisTransformDM_Internal(dm, &tdm);CHKERRQ(ierr); 5170 ierr = DMGetBasisTransformVec_Internal(dm, &tv);CHKERRQ(ierr); 5171 ierr = DMGetLocalSection(dm, §ion);CHKERRQ(ierr); 5172 ierr = PetscObjectTypeCompare((PetscObject) JacP, MATIS, &isMatISP);CHKERRQ(ierr); 5173 ierr = DMGetGlobalSection(dm, &globalSection);CHKERRQ(ierr); 5174 if (isMatISP) {ierr = DMPlexGetSubdomainSection(dm, &subSection);CHKERRQ(ierr);} 5175 ierr = ISGetLocalSize(cellIS, &numCells);CHKERRQ(ierr); 5176 ierr = ISGetPointRange(cellIS, &cStart, &cEnd, &cells);CHKERRQ(ierr); 5177 ierr = DMGetCellDS(dm, cells ? cells[cStart] : cStart, &prob);CHKERRQ(ierr); 5178 ierr = PetscDSGetNumFields(prob, &Nf);CHKERRQ(ierr); 5179 ierr = PetscDSGetTotalDimension(prob, &totDim);CHKERRQ(ierr); 5180 ierr = PetscDSHasJacobian(prob, &hasJac);CHKERRQ(ierr); 5181 ierr = PetscDSHasJacobianPreconditioner(prob, &hasPrec);CHKERRQ(ierr); 5182 /* user passed in the same matrix, avoid double contributions and 5183 only assemble the Jacobian */ 5184 if (hasJac && Jac == JacP) hasPrec = PETSC_FALSE; 5185 ierr = PetscDSHasDynamicJacobian(prob, &hasDyn);CHKERRQ(ierr); 5186 hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE; 5187 ierr = PetscObjectQuery((PetscObject) dm, "dmAux", (PetscObject *) &dmAux);CHKERRQ(ierr); 5188 ierr = PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &A);CHKERRQ(ierr); 5189 if (dmAux) { 5190 ierr = DMGetEnclosureRelation(dmAux, dm, &encAux);CHKERRQ(ierr); 5191 ierr = DMConvert(dmAux, DMPLEX, &plex);CHKERRQ(ierr); 5192 ierr = DMGetLocalSection(plex, §ionAux);CHKERRQ(ierr); 5193 ierr = DMGetDS(dmAux, &probAux);CHKERRQ(ierr); 5194 ierr = PetscDSGetTotalDimension(probAux, &totDimAux);CHKERRQ(ierr); 5195 } 5196 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); 5197 if (dmAux) {ierr = PetscMalloc1(numCells*totDimAux, &a);CHKERRQ(ierr);} 5198 ierr = DMGetCoordinateField(dm, &coordField);CHKERRQ(ierr); 5199 for (c = cStart; c < cEnd; ++c) { 5200 const PetscInt cell = cells ? cells[c] : c; 5201 const PetscInt cind = c - cStart; 5202 PetscScalar *x = NULL, *x_t = NULL; 5203 PetscInt i; 5204 5205 ierr = DMPlexVecGetClosure(dm, section, X, cell, NULL, &x);CHKERRQ(ierr); 5206 for (i = 0; i < totDim; ++i) u[cind*totDim+i] = x[i]; 5207 ierr = DMPlexVecRestoreClosure(dm, section, X, cell, NULL, &x);CHKERRQ(ierr); 5208 if (X_t) { 5209 ierr = DMPlexVecGetClosure(dm, section, X_t, cell, NULL, &x_t);CHKERRQ(ierr); 5210 for (i = 0; i < totDim; ++i) u_t[cind*totDim+i] = x_t[i]; 5211 ierr = DMPlexVecRestoreClosure(dm, section, X_t, cell, NULL, &x_t);CHKERRQ(ierr); 5212 } 5213 if (dmAux) { 5214 PetscInt subcell; 5215 ierr = DMGetEnclosurePoint(dmAux, dm, encAux, cell, &subcell);CHKERRQ(ierr); 5216 ierr = DMPlexVecGetClosure(plex, sectionAux, A, subcell, NULL, &x);CHKERRQ(ierr); 5217 for (i = 0; i < totDimAux; ++i) a[cind*totDimAux+i] = x[i]; 5218 ierr = DMPlexVecRestoreClosure(plex, sectionAux, A, subcell, NULL, &x);CHKERRQ(ierr); 5219 } 5220 } 5221 if (hasJac) {ierr = PetscArrayzero(elemMat, numCells*totDim*totDim);CHKERRQ(ierr);} 5222 if (hasPrec) {ierr = PetscArrayzero(elemMatP, numCells*totDim*totDim);CHKERRQ(ierr);} 5223 if (hasDyn) {ierr = PetscArrayzero(elemMatD, numCells*totDim*totDim);CHKERRQ(ierr);} 5224 for (fieldI = 0; fieldI < Nf; ++fieldI) { 5225 PetscClassId id; 5226 PetscFE fe; 5227 PetscQuadrature qGeom = NULL; 5228 PetscInt Nb; 5229 /* Conforming batches */ 5230 PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize; 5231 /* Remainder */ 5232 PetscInt Nr, offset, Nq; 5233 PetscInt maxDegree; 5234 PetscFEGeom *cgeomFEM, *chunkGeom = NULL, *remGeom = NULL; 5235 5236 ierr = PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fe);CHKERRQ(ierr); 5237 ierr = PetscObjectGetClassId((PetscObject) fe, &id);CHKERRQ(ierr); 5238 if (id == PETSCFV_CLASSID) {hasFV = PETSC_TRUE; continue;} 5239 ierr = PetscFEGetDimension(fe, &Nb);CHKERRQ(ierr); 5240 ierr = PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);CHKERRQ(ierr); 5241 ierr = DMFieldGetDegree(coordField,cellIS,NULL,&maxDegree);CHKERRQ(ierr); 5242 if (maxDegree <= 1) { 5243 ierr = DMFieldCreateDefaultQuadrature(coordField,cellIS,&qGeom);CHKERRQ(ierr); 5244 } 5245 if (!qGeom) { 5246 ierr = PetscFEGetQuadrature(fe,&qGeom);CHKERRQ(ierr); 5247 ierr = PetscObjectReference((PetscObject)qGeom);CHKERRQ(ierr); 5248 } 5249 ierr = PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL);CHKERRQ(ierr); 5250 ierr = DMSNESGetFEGeom(coordField,cellIS,qGeom,PETSC_FALSE,&cgeomFEM);CHKERRQ(ierr); 5251 blockSize = Nb; 5252 batchSize = numBlocks * blockSize; 5253 ierr = PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);CHKERRQ(ierr); 5254 numChunks = numCells / (numBatches*batchSize); 5255 Ne = numChunks*numBatches*batchSize; 5256 Nr = numCells % (numBatches*batchSize); 5257 offset = numCells - Nr; 5258 ierr = PetscFEGeomGetChunk(cgeomFEM,0,offset,&chunkGeom);CHKERRQ(ierr); 5259 ierr = PetscFEGeomGetChunk(cgeomFEM,offset,numCells,&remGeom);CHKERRQ(ierr); 5260 for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 5261 if (hasJac) { 5262 ierr = PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, fieldI, fieldJ, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat);CHKERRQ(ierr); 5263 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); 5264 } 5265 if (hasPrec) { 5266 ierr = PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, fieldI, fieldJ, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatP);CHKERRQ(ierr); 5267 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); 5268 } 5269 if (hasDyn) { 5270 ierr = PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, fieldI, fieldJ, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatD);CHKERRQ(ierr); 5271 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); 5272 } 5273 } 5274 ierr = PetscFEGeomRestoreChunk(cgeomFEM,offset,numCells,&remGeom);CHKERRQ(ierr); 5275 ierr = PetscFEGeomRestoreChunk(cgeomFEM,0,offset,&chunkGeom);CHKERRQ(ierr); 5276 ierr = DMSNESRestoreFEGeom(coordField,cellIS,qGeom,PETSC_FALSE,&cgeomFEM);CHKERRQ(ierr); 5277 ierr = PetscQuadratureDestroy(&qGeom);CHKERRQ(ierr); 5278 } 5279 /* Add contribution from X_t */ 5280 if (hasDyn) {for (c = 0; c < numCells*totDim*totDim; ++c) elemMat[c] += X_tShift*elemMatD[c];} 5281 if (hasFV) { 5282 PetscClassId id; 5283 PetscFV fv; 5284 PetscInt offsetI, NcI, NbI = 1, fc, f; 5285 5286 for (fieldI = 0; fieldI < Nf; ++fieldI) { 5287 ierr = PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fv);CHKERRQ(ierr); 5288 ierr = PetscDSGetFieldOffset(prob, fieldI, &offsetI);CHKERRQ(ierr); 5289 ierr = PetscObjectGetClassId((PetscObject) fv, &id);CHKERRQ(ierr); 5290 if (id != PETSCFV_CLASSID) continue; 5291 /* Put in the identity */ 5292 ierr = PetscFVGetNumComponents(fv, &NcI);CHKERRQ(ierr); 5293 for (c = cStart; c < cEnd; ++c) { 5294 const PetscInt cind = c - cStart; 5295 const PetscInt eOffset = cind*totDim*totDim; 5296 for (fc = 0; fc < NcI; ++fc) { 5297 for (f = 0; f < NbI; ++f) { 5298 const PetscInt i = offsetI + f*NcI+fc; 5299 if (hasPrec) { 5300 if (hasJac) {elemMat[eOffset+i*totDim+i] = 1.0;} 5301 elemMatP[eOffset+i*totDim+i] = 1.0; 5302 } else {elemMat[eOffset+i*totDim+i] = 1.0;} 5303 } 5304 } 5305 } 5306 } 5307 /* No allocated space for FV stuff, so ignore the zero entries */ 5308 ierr = MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE);CHKERRQ(ierr); 5309 } 5310 /* Insert values into matrix */ 5311 isMatIS = PETSC_FALSE; 5312 if (hasPrec && hasJac) { 5313 ierr = PetscObjectTypeCompare((PetscObject) JacP, MATIS, &isMatIS);CHKERRQ(ierr); 5314 } 5315 if (isMatIS && !subSection) { 5316 ierr = DMPlexGetSubdomainSection(dm, &subSection);CHKERRQ(ierr); 5317 } 5318 for (c = cStart; c < cEnd; ++c) { 5319 const PetscInt cell = cells ? cells[c] : c; 5320 const PetscInt cind = c - cStart; 5321 5322 /* Transform to global basis before insertion in Jacobian */ 5323 if (transform) {ierr = DMPlexBasisTransformPointTensor_Internal(dm, tdm, tv, cell, PETSC_TRUE, totDim, &elemMat[cind*totDim*totDim]);CHKERRQ(ierr);} 5324 if (hasPrec) { 5325 if (hasJac) { 5326 if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind*totDim*totDim]);CHKERRQ(ierr);} 5327 if (!isMatIS) { 5328 ierr = DMPlexMatSetClosure(dm, section, globalSection, Jac, cell, &elemMat[cind*totDim*totDim], ADD_VALUES);CHKERRQ(ierr); 5329 } else { 5330 Mat lJ; 5331 5332 ierr = MatISGetLocalMat(Jac,&lJ);CHKERRQ(ierr); 5333 ierr = DMPlexMatSetClosure(dm, section, subSection, lJ, cell, &elemMat[cind*totDim*totDim], ADD_VALUES);CHKERRQ(ierr); 5334 } 5335 } 5336 if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatP[cind*totDim*totDim]);CHKERRQ(ierr);} 5337 if (!isMatISP) { 5338 ierr = DMPlexMatSetClosure(dm, section, globalSection, JacP, cell, &elemMatP[cind*totDim*totDim], ADD_VALUES);CHKERRQ(ierr); 5339 } else { 5340 Mat lJ; 5341 5342 ierr = MatISGetLocalMat(JacP,&lJ);CHKERRQ(ierr); 5343 ierr = DMPlexMatSetClosure(dm, section, subSection, lJ, cell, &elemMatP[cind*totDim*totDim], ADD_VALUES);CHKERRQ(ierr); 5344 } 5345 } else { 5346 if (hasJac) { 5347 if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind*totDim*totDim]);CHKERRQ(ierr);} 5348 if (!isMatISP) { 5349 ierr = DMPlexMatSetClosure(dm, section, globalSection, JacP, cell, &elemMat[cind*totDim*totDim], ADD_VALUES);CHKERRQ(ierr); 5350 } else { 5351 Mat lJ; 5352 5353 ierr = MatISGetLocalMat(JacP,&lJ);CHKERRQ(ierr); 5354 ierr = DMPlexMatSetClosure(dm, section, subSection, lJ, cell, &elemMat[cind*totDim*totDim], ADD_VALUES);CHKERRQ(ierr); 5355 } 5356 } 5357 } 5358 } 5359 ierr = ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);CHKERRQ(ierr); 5360 if (hasFV) {ierr = MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_FALSE);CHKERRQ(ierr);} 5361 ierr = PetscFree5(u,u_t,elemMat,elemMatP,elemMatD);CHKERRQ(ierr); 5362 if (dmAux) { 5363 ierr = PetscFree(a);CHKERRQ(ierr); 5364 ierr = DMDestroy(&plex);CHKERRQ(ierr); 5365 } 5366 /* Compute boundary integrals */ 5367 ierr = DMPlexComputeBdJacobian_Internal(dm, X, X_t, t, X_tShift, Jac, JacP, user);CHKERRQ(ierr); 5368 /* Assemble matrix */ 5369 if (hasJac && hasPrec) { 5370 ierr = MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 5371 ierr = MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 5372 } 5373 ierr = MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 5374 ierr = MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 5375 ierr = PetscLogEventEnd(DMPLEX_JacobianFEM,dm,0,0,0);CHKERRQ(ierr); 5376 PetscFunctionReturn(0); 5377 } 5378 5379 PetscErrorCode DMPlexComputeJacobian_Hybrid_Internal(DM dm, IS cellIS, PetscReal t, PetscReal X_tShift, Vec locX, Vec locX_t, Mat Jac, Mat JacP, void *user) 5380 { 5381 DM_Plex *mesh = (DM_Plex *) dm->data; 5382 const char *name = "Hybrid Jacobian"; 5383 DM dmAux = NULL; 5384 DM plex = NULL; 5385 DM plexA = NULL; 5386 DMLabel ghostLabel = NULL; 5387 PetscDS prob = NULL; 5388 PetscDS probAux = NULL; 5389 PetscSection section = NULL; 5390 DMField coordField = NULL; 5391 Vec locA; 5392 PetscScalar *u = NULL, *u_t, *a = NULL; 5393 PetscScalar *elemMat, *elemMatP; 5394 PetscSection globalSection, subSection, sectionAux; 5395 IS chunkIS; 5396 const PetscInt *cells; 5397 PetscInt *faces; 5398 PetscInt cStart, cEnd, numCells; 5399 PetscInt Nf, fieldI, fieldJ, totDim, totDimAux, numChunks, cellChunkSize, chunk; 5400 PetscInt maxDegree = PETSC_MAX_INT; 5401 PetscQuadrature affineQuad = NULL, *quads = NULL; 5402 PetscFEGeom *affineGeom = NULL, **geoms = NULL; 5403 PetscBool isMatIS = PETSC_FALSE, isMatISP = PETSC_FALSE, hasBdJac, hasBdPrec; 5404 PetscErrorCode ierr; 5405 5406 PetscFunctionBegin; 5407 ierr = PetscLogEventBegin(DMPLEX_JacobianFEM,dm,0,0,0);CHKERRQ(ierr); 5408 ierr = ISGetLocalSize(cellIS, &numCells);CHKERRQ(ierr); 5409 ierr = ISGetPointRange(cellIS, &cStart, &cEnd, &cells);CHKERRQ(ierr); 5410 ierr = DMConvert(dm, DMPLEX, &plex);CHKERRQ(ierr); 5411 ierr = DMGetSection(dm, §ion);CHKERRQ(ierr); 5412 ierr = DMGetGlobalSection(dm, &globalSection);CHKERRQ(ierr); 5413 ierr = DMGetLabel(dm, "ghost", &ghostLabel);CHKERRQ(ierr); 5414 ierr = DMGetCellDS(dm, cStart, &prob);CHKERRQ(ierr); 5415 ierr = PetscDSGetNumFields(prob, &Nf);CHKERRQ(ierr); 5416 ierr = PetscDSGetTotalDimension(prob, &totDim);CHKERRQ(ierr); 5417 ierr = PetscDSHasBdJacobian(prob, &hasBdJac);CHKERRQ(ierr); 5418 ierr = PetscDSHasBdJacobianPreconditioner(prob, &hasBdPrec);CHKERRQ(ierr); 5419 ierr = PetscObjectTypeCompare((PetscObject) JacP, MATIS, &isMatISP);CHKERRQ(ierr); 5420 if (isMatISP) {ierr = DMPlexGetSubdomainSection(plex, &subSection);CHKERRQ(ierr);} 5421 if (hasBdPrec && hasBdJac) {ierr = PetscObjectTypeCompare((PetscObject) JacP, MATIS, &isMatIS);CHKERRQ(ierr);} 5422 if (isMatIS && !subSection) {ierr = DMPlexGetSubdomainSection(plex, &subSection);CHKERRQ(ierr);} 5423 ierr = PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &locA);CHKERRQ(ierr); 5424 if (locA) { 5425 ierr = VecGetDM(locA, &dmAux);CHKERRQ(ierr); 5426 ierr = DMConvert(dmAux, DMPLEX, &plexA);CHKERRQ(ierr); 5427 ierr = DMGetSection(dmAux, §ionAux);CHKERRQ(ierr); 5428 ierr = DMGetCellDS(dmAux, cStart, &probAux);CHKERRQ(ierr); 5429 ierr = PetscDSGetTotalDimension(probAux, &totDimAux);CHKERRQ(ierr); 5430 } 5431 ierr = DMGetCoordinateField(dm, &coordField);CHKERRQ(ierr); 5432 ierr = DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree);CHKERRQ(ierr); 5433 if (maxDegree > 1) { 5434 PetscInt f; 5435 ierr = PetscCalloc2(Nf,&quads,Nf,&geoms);CHKERRQ(ierr); 5436 for (f = 0; f < Nf; ++f) { 5437 PetscFE fe; 5438 5439 ierr = PetscDSGetDiscretization(prob, f, (PetscObject *) &fe);CHKERRQ(ierr); 5440 if (fe) { 5441 ierr = PetscFEGetQuadrature(fe, &quads[f]);CHKERRQ(ierr); 5442 ierr = PetscObjectReference((PetscObject) quads[f]);CHKERRQ(ierr); 5443 } 5444 } 5445 } 5446 cellChunkSize = numCells; 5447 numChunks = !numCells ? 0 : PetscCeilReal(((PetscReal) numCells)/cellChunkSize); 5448 ierr = PetscCalloc1(2*cellChunkSize, &faces);CHKERRQ(ierr); 5449 ierr = ISCreateGeneral(PETSC_COMM_SELF, cellChunkSize, faces, PETSC_USE_POINTER, &chunkIS);CHKERRQ(ierr); 5450 ierr = DMPlexGetCellFields(dm, cellIS, locX, locX_t, locA, &u, &u_t, &a);CHKERRQ(ierr); 5451 ierr = DMGetWorkArray(dm, hasBdJac ? cellChunkSize*totDim*totDim : 0, MPIU_SCALAR, &elemMat);CHKERRQ(ierr); 5452 ierr = DMGetWorkArray(dm, hasBdPrec ? cellChunkSize*totDim*totDim : 0, MPIU_SCALAR, &elemMatP);CHKERRQ(ierr); 5453 for (chunk = 0; chunk < numChunks; ++chunk) { 5454 PetscInt cS = cStart+chunk*cellChunkSize, cE = PetscMin(cS+cellChunkSize, cEnd), numCells = cE - cS, c; 5455 5456 if (hasBdJac) {ierr = PetscMemzero(elemMat, numCells*totDim*totDim * sizeof(PetscScalar));CHKERRQ(ierr);} 5457 if (hasBdPrec) {ierr = PetscMemzero(elemMatP, numCells*totDim*totDim * sizeof(PetscScalar));CHKERRQ(ierr);} 5458 /* Get faces */ 5459 for (c = cS; c < cE; ++c) { 5460 const PetscInt cell = cells ? cells[c] : c; 5461 const PetscInt *cone; 5462 ierr = DMPlexGetCone(plex, cell, &cone);CHKERRQ(ierr); 5463 faces[(c-cS)*2+0] = cone[0]; 5464 faces[(c-cS)*2+1] = cone[1]; 5465 } 5466 ierr = ISGeneralSetIndices(chunkIS, cellChunkSize, faces, PETSC_USE_POINTER);CHKERRQ(ierr); 5467 if (maxDegree <= 1) { 5468 if (!affineQuad) {ierr = DMFieldCreateDefaultQuadrature(coordField, chunkIS, &affineQuad);CHKERRQ(ierr);} 5469 if (affineQuad) {ierr = DMSNESGetFEGeom(coordField, chunkIS, affineQuad, PETSC_TRUE, &affineGeom);CHKERRQ(ierr);} 5470 } else { 5471 PetscInt f; 5472 for (f = 0; f < Nf; ++f) { 5473 if (quads[f]) {ierr = DMSNESGetFEGeom(coordField, chunkIS, quads[f], PETSC_TRUE, &geoms[f]);CHKERRQ(ierr);} 5474 } 5475 } 5476 5477 for (fieldI = 0; fieldI < Nf; ++fieldI) { 5478 PetscFE feI; 5479 PetscFEGeom *geom = affineGeom ? affineGeom : geoms[fieldI]; 5480 PetscFEGeom *chunkGeom = NULL, *remGeom = NULL; 5481 PetscQuadrature quad = affineQuad ? affineQuad : quads[fieldI]; 5482 PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset, Nq, Nb; 5483 5484 ierr = PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &feI);CHKERRQ(ierr); 5485 if (!feI) continue; 5486 ierr = PetscFEGetTileSizes(feI, NULL, &numBlocks, NULL, &numBatches);CHKERRQ(ierr); 5487 ierr = PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL);CHKERRQ(ierr); 5488 ierr = PetscFEGetDimension(feI, &Nb);CHKERRQ(ierr); 5489 blockSize = Nb; 5490 batchSize = numBlocks * blockSize; 5491 ierr = PetscFESetTileSizes(feI, blockSize, numBlocks, batchSize, numBatches);CHKERRQ(ierr); 5492 numChunks = numCells / (numBatches*batchSize); 5493 Ne = numChunks*numBatches*batchSize; 5494 Nr = numCells % (numBatches*batchSize); 5495 offset = numCells - Nr; 5496 ierr = PetscFEGeomGetChunk(geom,0,offset,&chunkGeom);CHKERRQ(ierr); 5497 ierr = PetscFEGeomGetChunk(geom,offset,numCells,&remGeom);CHKERRQ(ierr); 5498 for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 5499 PetscFE feJ; 5500 5501 ierr = PetscDSGetDiscretization(prob, fieldJ, (PetscObject *) &feJ);CHKERRQ(ierr); 5502 if (!feJ) continue; 5503 if (hasBdJac) { 5504 ierr = PetscFEIntegrateHybridJacobian(prob, PETSCFE_JACOBIAN, fieldI, fieldJ, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMat);CHKERRQ(ierr); 5505 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); 5506 } 5507 if (hasBdPrec) { 5508 ierr = PetscFEIntegrateHybridJacobian(prob, PETSCFE_JACOBIAN_PRE, fieldI, fieldJ, Ne, chunkGeom, u, u_t, probAux, a, t, X_tShift, elemMatP);CHKERRQ(ierr); 5509 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); 5510 } 5511 } 5512 ierr = PetscFEGeomRestoreChunk(geom,offset,numCells,&remGeom);CHKERRQ(ierr); 5513 ierr = PetscFEGeomRestoreChunk(geom,0,offset,&chunkGeom);CHKERRQ(ierr); 5514 } 5515 /* Insert values into matrix */ 5516 for (c = cS; c < cE; ++c) { 5517 const PetscInt cell = cells ? cells[c] : c; 5518 const PetscInt cind = c - cS; 5519 5520 if (hasBdPrec) { 5521 if (hasBdJac) { 5522 if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind*totDim*totDim]);CHKERRQ(ierr);} 5523 if (!isMatIS) { 5524 ierr = DMPlexMatSetClosure(plex, section, globalSection, Jac, cell, &elemMat[cind*totDim*totDim], ADD_VALUES);CHKERRQ(ierr); 5525 } else { 5526 Mat lJ; 5527 5528 ierr = MatISGetLocalMat(Jac,&lJ);CHKERRQ(ierr); 5529 ierr = DMPlexMatSetClosure(plex, section, subSection, lJ, cell, &elemMat[cind*totDim*totDim], ADD_VALUES);CHKERRQ(ierr); 5530 } 5531 } 5532 if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(cell, name, totDim, totDim, &elemMatP[cind*totDim*totDim]);CHKERRQ(ierr);} 5533 if (!isMatISP) { 5534 ierr = DMPlexMatSetClosure(plex, section, globalSection, JacP, cell, &elemMatP[cind*totDim*totDim], ADD_VALUES);CHKERRQ(ierr); 5535 } else { 5536 Mat lJ; 5537 5538 ierr = MatISGetLocalMat(JacP,&lJ);CHKERRQ(ierr); 5539 ierr = DMPlexMatSetClosure(plex, section, subSection, lJ, cell, &elemMatP[cind*totDim*totDim], ADD_VALUES);CHKERRQ(ierr); 5540 } 5541 } else if (hasBdJac) { 5542 if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[cind*totDim*totDim]);CHKERRQ(ierr);} 5543 if (!isMatISP) { 5544 ierr = DMPlexMatSetClosure(plex, section, globalSection, JacP, cell, &elemMat[cind*totDim*totDim], ADD_VALUES);CHKERRQ(ierr); 5545 } else { 5546 Mat lJ; 5547 5548 ierr = MatISGetLocalMat(JacP,&lJ);CHKERRQ(ierr); 5549 ierr = DMPlexMatSetClosure(plex, section, subSection, lJ, cell, &elemMat[cind*totDim*totDim], ADD_VALUES);CHKERRQ(ierr); 5550 } 5551 } 5552 } 5553 } 5554 ierr = DMPlexRestoreCellFields(dm, cellIS, locX, locX_t, locA, &u, &u_t, &a);CHKERRQ(ierr); 5555 ierr = DMRestoreWorkArray(dm, hasBdJac ? cellChunkSize*totDim*totDim : 0, MPIU_SCALAR, &elemMat);CHKERRQ(ierr); 5556 ierr = DMRestoreWorkArray(dm, hasBdPrec ? cellChunkSize*totDim*totDim : 0, MPIU_SCALAR, &elemMatP);CHKERRQ(ierr); 5557 ierr = PetscFree(faces);CHKERRQ(ierr); 5558 ierr = ISDestroy(&chunkIS);CHKERRQ(ierr); 5559 ierr = ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);CHKERRQ(ierr); 5560 if (maxDegree <= 1) { 5561 ierr = DMSNESRestoreFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom);CHKERRQ(ierr); 5562 ierr = PetscQuadratureDestroy(&affineQuad);CHKERRQ(ierr); 5563 } else { 5564 PetscInt f; 5565 for (f = 0; f < Nf; ++f) { 5566 if (geoms) {ierr = DMSNESRestoreFEGeom(coordField,cellIS,quads[f],PETSC_FALSE, &geoms[f]);CHKERRQ(ierr);} 5567 if (quads) {ierr = PetscQuadratureDestroy(&quads[f]);CHKERRQ(ierr);} 5568 } 5569 ierr = PetscFree2(quads,geoms);CHKERRQ(ierr); 5570 } 5571 if (dmAux) {ierr = DMDestroy(&plexA);CHKERRQ(ierr);} 5572 ierr = DMDestroy(&plex);CHKERRQ(ierr); 5573 /* Assemble matrix */ 5574 if (hasBdJac && hasBdPrec) { 5575 ierr = MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 5576 ierr = MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 5577 } 5578 ierr = MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 5579 ierr = MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 5580 ierr = PetscLogEventEnd(DMPLEX_JacobianFEM,dm,0,0,0);CHKERRQ(ierr); 5581 PetscFunctionReturn(0); 5582 } 5583