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