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