1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petscsf.h> 3 4 #include <petsc/private/hashsetij.h> 5 #include <petsc/private/petscfeimpl.h> 6 #include <petsc/private/petscfvimpl.h> 7 8 static PetscErrorCode DMPlexConvertPlex(DM dm, DM *plex, PetscBool copy) 9 { 10 PetscBool isPlex; 11 PetscErrorCode ierr; 12 13 PetscFunctionBegin; 14 ierr = PetscObjectTypeCompare((PetscObject) dm, DMPLEX, &isPlex);CHKERRQ(ierr); 15 if (isPlex) { 16 *plex = dm; 17 ierr = PetscObjectReference((PetscObject) dm);CHKERRQ(ierr); 18 } else { 19 ierr = PetscObjectQuery((PetscObject) dm, "dm_plex", (PetscObject *) plex);CHKERRQ(ierr); 20 if (!*plex) { 21 ierr = DMConvert(dm,DMPLEX,plex);CHKERRQ(ierr); 22 ierr = PetscObjectCompose((PetscObject) dm, "dm_plex", (PetscObject) *plex);CHKERRQ(ierr); 23 if (copy) { 24 const char *comps[3] = {"A", "dmAux"}; 25 PetscObject obj; 26 PetscInt i; 27 28 { 29 /* Run the subdomain hook (this will copy the DMSNES/DMTS) */ 30 DMSubDomainHookLink link; 31 for (link = dm->subdomainhook; link; link = link->next) { 32 if (link->ddhook) {ierr = (*link->ddhook)(dm, *plex, link->ctx);CHKERRQ(ierr);} 33 } 34 } 35 for (i = 0; i < 3; i++) { 36 ierr = PetscObjectQuery((PetscObject) dm, comps[i], &obj);CHKERRQ(ierr); 37 ierr = PetscObjectCompose((PetscObject) *plex, comps[i], obj);CHKERRQ(ierr); 38 } 39 } 40 } else { 41 ierr = PetscObjectReference((PetscObject) *plex);CHKERRQ(ierr); 42 } 43 } 44 PetscFunctionReturn(0); 45 } 46 47 static PetscErrorCode PetscContainerUserDestroy_PetscFEGeom (void *ctx) 48 { 49 PetscFEGeom *geom = (PetscFEGeom *) ctx; 50 PetscErrorCode ierr; 51 52 PetscFunctionBegin; 53 ierr = PetscFEGeomDestroy(&geom);CHKERRQ(ierr); 54 PetscFunctionReturn(0); 55 } 56 57 static PetscErrorCode DMPlexGetFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom) 58 { 59 char composeStr[33] = {0}; 60 PetscObjectId id; 61 PetscContainer container; 62 PetscErrorCode ierr; 63 64 PetscFunctionBegin; 65 ierr = PetscObjectGetId((PetscObject)quad,&id);CHKERRQ(ierr); 66 ierr = PetscSNPrintf(composeStr, 32, "DMPlexGetFEGeom_%x\n", id);CHKERRQ(ierr); 67 ierr = PetscObjectQuery((PetscObject) pointIS, composeStr, (PetscObject *) &container);CHKERRQ(ierr); 68 if (container) { 69 ierr = PetscContainerGetPointer(container, (void **) geom);CHKERRQ(ierr); 70 } else { 71 ierr = DMFieldCreateFEGeom(coordField, pointIS, quad, faceData, geom);CHKERRQ(ierr); 72 ierr = PetscContainerCreate(PETSC_COMM_SELF,&container);CHKERRQ(ierr); 73 ierr = PetscContainerSetPointer(container, (void *) *geom);CHKERRQ(ierr); 74 ierr = PetscContainerSetUserDestroy(container, PetscContainerUserDestroy_PetscFEGeom);CHKERRQ(ierr); 75 ierr = PetscObjectCompose((PetscObject) pointIS, composeStr, (PetscObject) container);CHKERRQ(ierr); 76 ierr = PetscContainerDestroy(&container);CHKERRQ(ierr); 77 } 78 PetscFunctionReturn(0); 79 } 80 81 static PetscErrorCode DMPlexRestoreFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom) 82 { 83 PetscFunctionBegin; 84 *geom = NULL; 85 PetscFunctionReturn(0); 86 } 87 88 /*@ 89 DMPlexGetScale - Get the scale for the specified fundamental unit 90 91 Not collective 92 93 Input Arguments: 94 + dm - the DM 95 - unit - The SI unit 96 97 Output Argument: 98 . scale - The value used to scale all quantities with this unit 99 100 Level: advanced 101 102 .seealso: DMPlexSetScale(), PetscUnit 103 @*/ 104 PetscErrorCode DMPlexGetScale(DM dm, PetscUnit unit, PetscReal *scale) 105 { 106 DM_Plex *mesh = (DM_Plex*) dm->data; 107 108 PetscFunctionBegin; 109 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 110 PetscValidPointer(scale, 3); 111 *scale = mesh->scale[unit]; 112 PetscFunctionReturn(0); 113 } 114 115 /*@ 116 DMPlexSetScale - Set the scale for the specified fundamental unit 117 118 Not collective 119 120 Input Arguments: 121 + dm - the DM 122 . unit - The SI unit 123 - scale - The value used to scale all quantities with this unit 124 125 Level: advanced 126 127 .seealso: DMPlexGetScale(), PetscUnit 128 @*/ 129 PetscErrorCode DMPlexSetScale(DM dm, PetscUnit unit, PetscReal scale) 130 { 131 DM_Plex *mesh = (DM_Plex*) dm->data; 132 133 PetscFunctionBegin; 134 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 135 mesh->scale[unit] = scale; 136 PetscFunctionReturn(0); 137 } 138 139 static PetscErrorCode DMPlexProjectRigidBody_Private(PetscInt dim, PetscReal t, const PetscReal X[], PetscInt Nf, PetscScalar *mode, void *ctx) 140 { 141 const PetscInt eps[3][3][3] = {{{0, 0, 0}, {0, 0, 1}, {0, -1, 0}}, {{0, 0, -1}, {0, 0, 0}, {1, 0, 0}}, {{0, 1, 0}, {-1, 0, 0}, {0, 0, 0}}}; 142 PetscInt *ctxInt = (PetscInt *) ctx; 143 PetscInt dim2 = ctxInt[0]; 144 PetscInt d = ctxInt[1]; 145 PetscInt i, j, k = dim > 2 ? d - dim : d; 146 147 PetscFunctionBegin; 148 if (dim != dim2) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Input dimension %D does not match context dimension %D", dim, dim2); 149 for (i = 0; i < dim; i++) mode[i] = 0.; 150 if (d < dim) { 151 mode[d] = 1.; /* Translation along axis d */ 152 } else { 153 for (i = 0; i < dim; i++) { 154 for (j = 0; j < dim; j++) { 155 mode[j] += eps[i][j][k]*X[i]; /* Rotation about axis d */ 156 } 157 } 158 } 159 PetscFunctionReturn(0); 160 } 161 162 /*@ 163 DMPlexCreateRigidBody - For the default global section, create rigid body modes by function space interpolation 164 165 Collective on dm 166 167 Input Arguments: 168 . dm - the DM 169 170 Output Argument: 171 . sp - the null space 172 173 Note: This is necessary to provide a suitable coarse space for algebraic multigrid 174 175 Level: advanced 176 177 .seealso: MatNullSpaceCreate(), PCGAMG 178 @*/ 179 PetscErrorCode DMPlexCreateRigidBody(DM dm, MatNullSpace *sp) 180 { 181 MPI_Comm comm; 182 Vec mode[6]; 183 PetscSection section, globalSection; 184 PetscInt dim, dimEmbed, n, m, mmin, d, i, j; 185 PetscErrorCode ierr; 186 187 PetscFunctionBegin; 188 ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr); 189 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 190 ierr = DMGetCoordinateDim(dm, &dimEmbed);CHKERRQ(ierr); 191 if (dim == 1) { 192 ierr = MatNullSpaceCreate(comm, PETSC_TRUE, 0, NULL, sp);CHKERRQ(ierr); 193 PetscFunctionReturn(0); 194 } 195 ierr = DMGetLocalSection(dm, §ion);CHKERRQ(ierr); 196 ierr = DMGetGlobalSection(dm, &globalSection);CHKERRQ(ierr); 197 ierr = PetscSectionGetConstrainedStorageSize(globalSection, &n);CHKERRQ(ierr); 198 m = (dim*(dim+1))/2; 199 ierr = VecCreate(comm, &mode[0]);CHKERRQ(ierr); 200 ierr = VecSetSizes(mode[0], n, PETSC_DETERMINE);CHKERRQ(ierr); 201 ierr = VecSetUp(mode[0]);CHKERRQ(ierr); 202 ierr = VecGetSize(mode[0], &n);CHKERRQ(ierr); 203 mmin = PetscMin(m, n); 204 for (i = 1; i < m; ++i) {ierr = VecDuplicate(mode[0], &mode[i]);CHKERRQ(ierr);} 205 for (d = 0; d < m; d++) { 206 PetscInt ctx[2]; 207 PetscErrorCode (*func)(PetscInt, PetscReal, const PetscReal *, PetscInt, PetscScalar *, void *) = DMPlexProjectRigidBody_Private; 208 void *voidctx = (void *) (&ctx[0]); 209 210 ctx[0] = dimEmbed; 211 ctx[1] = d; 212 ierr = DMProjectFunction(dm, 0.0, &func, &voidctx, INSERT_VALUES, mode[d]);CHKERRQ(ierr); 213 } 214 /* Orthonormalize system */ 215 for (i = 0; i < mmin; ++i) { 216 PetscScalar dots[6]; 217 218 ierr = VecNormalize(mode[i], NULL);CHKERRQ(ierr); 219 ierr = VecMDot(mode[i], mmin-i-1, mode+i+1, dots+i+1);CHKERRQ(ierr); 220 for (j = i+1; j < mmin; ++j) { 221 dots[j] *= -1.0; 222 ierr = VecAXPY(mode[j], dots[j], mode[i]);CHKERRQ(ierr); 223 } 224 } 225 ierr = MatNullSpaceCreate(comm, PETSC_FALSE, mmin, mode, sp);CHKERRQ(ierr); 226 for (i = 0; i < m; ++i) {ierr = VecDestroy(&mode[i]);CHKERRQ(ierr);} 227 PetscFunctionReturn(0); 228 } 229 230 /*@ 231 DMPlexCreateRigidBodies - For the default global section, create rigid body modes by function space interpolation 232 233 Collective on dm 234 235 Input Arguments: 236 + dm - the DM 237 . nb - The number of bodies 238 . label - The DMLabel marking each domain 239 . nids - The number of ids per body 240 - ids - An array of the label ids in sequence for each domain 241 242 Output Argument: 243 . sp - the null space 244 245 Note: This is necessary to provide a suitable coarse space for algebraic multigrid 246 247 Level: advanced 248 249 .seealso: MatNullSpaceCreate() 250 @*/ 251 PetscErrorCode DMPlexCreateRigidBodies(DM dm, PetscInt nb, DMLabel label, const PetscInt nids[], const PetscInt ids[], MatNullSpace *sp) 252 { 253 MPI_Comm comm; 254 PetscSection section, globalSection; 255 Vec *mode; 256 PetscScalar *dots; 257 PetscInt dim, dimEmbed, n, m, b, d, i, j, off; 258 PetscErrorCode ierr; 259 260 PetscFunctionBegin; 261 ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr); 262 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 263 ierr = DMGetCoordinateDim(dm, &dimEmbed);CHKERRQ(ierr); 264 ierr = DMGetLocalSection(dm, §ion);CHKERRQ(ierr); 265 ierr = DMGetGlobalSection(dm, &globalSection);CHKERRQ(ierr); 266 ierr = PetscSectionGetConstrainedStorageSize(globalSection, &n);CHKERRQ(ierr); 267 m = nb * (dim*(dim+1))/2; 268 ierr = PetscMalloc2(m, &mode, m, &dots);CHKERRQ(ierr); 269 ierr = VecCreate(comm, &mode[0]);CHKERRQ(ierr); 270 ierr = VecSetSizes(mode[0], n, PETSC_DETERMINE);CHKERRQ(ierr); 271 ierr = VecSetUp(mode[0]);CHKERRQ(ierr); 272 for (i = 1; i < m; ++i) {ierr = VecDuplicate(mode[0], &mode[i]);CHKERRQ(ierr);} 273 for (b = 0, off = 0; b < nb; ++b) { 274 for (d = 0; d < m/nb; ++d) { 275 PetscInt ctx[2]; 276 PetscErrorCode (*func)(PetscInt, PetscReal, const PetscReal *, PetscInt, PetscScalar *, void *) = DMPlexProjectRigidBody_Private; 277 void *voidctx = (void *) (&ctx[0]); 278 279 ctx[0] = dimEmbed; 280 ctx[1] = d; 281 ierr = DMProjectFunctionLabel(dm, 0.0, label, nids[b], &ids[off], 0, NULL, &func, &voidctx, INSERT_VALUES, mode[d]);CHKERRQ(ierr); 282 off += nids[b]; 283 } 284 } 285 /* Orthonormalize system */ 286 for (i = 0; i < m; ++i) { 287 PetscScalar dots[6]; 288 289 ierr = VecNormalize(mode[i], NULL);CHKERRQ(ierr); 290 ierr = VecMDot(mode[i], m-i-1, mode+i+1, dots+i+1);CHKERRQ(ierr); 291 for (j = i+1; j < m; ++j) { 292 dots[j] *= -1.0; 293 ierr = VecAXPY(mode[j], dots[j], mode[i]);CHKERRQ(ierr); 294 } 295 } 296 ierr = MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp);CHKERRQ(ierr); 297 for (i = 0; i< m; ++i) {ierr = VecDestroy(&mode[i]);CHKERRQ(ierr);} 298 ierr = PetscFree2(mode, dots);CHKERRQ(ierr); 299 PetscFunctionReturn(0); 300 } 301 302 /*@ 303 DMPlexSetMaxProjectionHeight - In DMPlexProjectXXXLocal() functions, the projected values of a basis function's dofs 304 are computed by associating the basis function with one of the mesh points in its transitively-closed support, and 305 evaluating the dual space basis of that point. A basis function is associated with the point in its 306 transitively-closed support whose mesh height is highest (w.r.t. DAG height), but not greater than the maximum 307 projection height, which is set with this function. By default, the maximum projection height is zero, which means 308 that only mesh cells are used to project basis functions. A height of one, for example, evaluates a cell-interior 309 basis functions using its cells dual space basis, but all other basis functions with the dual space basis of a face. 310 311 Input Parameters: 312 + dm - the DMPlex object 313 - height - the maximum projection height >= 0 314 315 Level: advanced 316 317 .seealso: DMPlexGetMaxProjectionHeight(), DMProjectFunctionLocal(), DMProjectFunctionLabelLocal() 318 @*/ 319 PetscErrorCode DMPlexSetMaxProjectionHeight(DM dm, PetscInt height) 320 { 321 DM_Plex *plex = (DM_Plex *) dm->data; 322 323 PetscFunctionBegin; 324 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 325 plex->maxProjectionHeight = height; 326 PetscFunctionReturn(0); 327 } 328 329 /*@ 330 DMPlexGetMaxProjectionHeight - Get the maximum height (w.r.t. DAG) of mesh points used to evaluate dual bases in 331 DMPlexProjectXXXLocal() functions. 332 333 Input Parameters: 334 . dm - the DMPlex object 335 336 Output Parameters: 337 . height - the maximum projection height 338 339 Level: intermediate 340 341 .seealso: DMPlexSetMaxProjectionHeight(), DMProjectFunctionLocal(), DMProjectFunctionLabelLocal() 342 @*/ 343 PetscErrorCode DMPlexGetMaxProjectionHeight(DM dm, PetscInt *height) 344 { 345 DM_Plex *plex = (DM_Plex *) dm->data; 346 347 PetscFunctionBegin; 348 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 349 *height = plex->maxProjectionHeight; 350 PetscFunctionReturn(0); 351 } 352 353 typedef struct { 354 PetscReal alpha; /* The first Euler angle, and in 2D the only one */ 355 PetscReal beta; /* The second Euler angle */ 356 PetscReal gamma; /* The third Euler angle */ 357 PetscInt dim; /* The dimension of R */ 358 PetscScalar *R; /* The rotation matrix, transforming a vector in the local basis to the global basis */ 359 PetscScalar *RT; /* The transposed rotation matrix, transforming a vector in the global basis to the local basis */ 360 } RotCtx; 361 362 /* 363 Note: Following https://en.wikipedia.org/wiki/Euler_angles, we will specify Euler angles by extrinsic rotations, meaning that 364 we rotate with respect to a fixed initial coordinate system, the local basis (x-y-z). The global basis (X-Y-Z) is reached as follows: 365 $ The XYZ system rotates about the z axis by alpha. The X axis is now at angle alpha with respect to the x axis. 366 $ The XYZ system rotates again about the x axis by beta. The Z axis is now at angle beta with respect to the z axis. 367 $ The XYZ system rotates a third time about the z axis by gamma. 368 */ 369 static PetscErrorCode DMPlexBasisTransformSetUp_Rotation_Internal(DM dm, void *ctx) 370 { 371 RotCtx *rc = (RotCtx *) ctx; 372 PetscInt dim = rc->dim; 373 PetscReal c1, s1, c2, s2, c3, s3; 374 PetscErrorCode ierr; 375 376 PetscFunctionBegin; 377 ierr = PetscMalloc2(PetscSqr(dim), &rc->R, PetscSqr(dim), &rc->RT);CHKERRQ(ierr); 378 switch (dim) { 379 case 2: 380 c1 = PetscCosReal(rc->alpha);s1 = PetscSinReal(rc->alpha); 381 rc->R[0] = c1;rc->R[1] = s1; 382 rc->R[2] = -s1;rc->R[3] = c1; 383 ierr = PetscArraycpy(rc->RT, rc->R, PetscSqr(dim));CHKERRQ(ierr); 384 DMPlex_Transpose2D_Internal(rc->RT);break; 385 break; 386 case 3: 387 c1 = PetscCosReal(rc->alpha);s1 = PetscSinReal(rc->alpha); 388 c2 = PetscCosReal(rc->beta); s2 = PetscSinReal(rc->beta); 389 c3 = PetscCosReal(rc->gamma);s3 = PetscSinReal(rc->gamma); 390 rc->R[0] = c1*c3 - c2*s1*s3;rc->R[1] = c3*s1 + c1*c2*s3;rc->R[2] = s2*s3; 391 rc->R[3] = -c1*s3 - c2*c3*s1;rc->R[4] = c1*c2*c3 - s1*s3; rc->R[5] = c3*s2; 392 rc->R[6] = s1*s2; rc->R[7] = -c1*s2; rc->R[8] = c2; 393 ierr = PetscArraycpy(rc->RT, rc->R, PetscSqr(dim));CHKERRQ(ierr); 394 DMPlex_Transpose3D_Internal(rc->RT);break; 395 break; 396 default: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_OUTOFRANGE, "Dimension %D not supported", dim); 397 } 398 PetscFunctionReturn(0); 399 } 400 401 static PetscErrorCode DMPlexBasisTransformDestroy_Rotation_Internal(DM dm, void *ctx) 402 { 403 RotCtx *rc = (RotCtx *) ctx; 404 PetscErrorCode ierr; 405 406 PetscFunctionBegin; 407 ierr = PetscFree2(rc->R, rc->RT);CHKERRQ(ierr); 408 ierr = PetscFree(rc);CHKERRQ(ierr); 409 PetscFunctionReturn(0); 410 } 411 412 static PetscErrorCode DMPlexBasisTransformGetMatrix_Rotation_Internal(DM dm, const PetscReal x[], PetscBool l2g, const PetscScalar **A, void *ctx) 413 { 414 RotCtx *rc = (RotCtx *) ctx; 415 416 PetscFunctionBeginHot; 417 PetscValidPointer(ctx, 5); 418 if (l2g) {*A = rc->R;} 419 else {*A = rc->RT;} 420 PetscFunctionReturn(0); 421 } 422 423 PetscErrorCode DMPlexBasisTransformApplyReal_Internal(DM dm, const PetscReal x[], PetscBool l2g, PetscInt dim, const PetscReal *y, PetscReal *z, void *ctx) 424 { 425 PetscErrorCode ierr; 426 427 PetscFunctionBegin; 428 #if defined(PETSC_USE_COMPLEX) 429 switch (dim) { 430 case 2: 431 { 432 PetscScalar yt[2], zt[2]; 433 434 yt[0] = y[0]; yt[1] = y[1]; 435 ierr = DMPlexBasisTransformApply_Internal(dm, x, l2g, dim, yt, zt, ctx);CHKERRQ(ierr); 436 z[0] = PetscRealPart(zt[0]); z[1] = PetscRealPart(zt[1]); 437 } 438 break; 439 case 3: 440 { 441 PetscScalar yt[3], zt[3]; 442 443 yt[0] = y[0]; yt[1] = y[1]; yt[2] = y[2]; 444 ierr = DMPlexBasisTransformApply_Internal(dm, x, l2g, dim, yt, zt, ctx);CHKERRQ(ierr); 445 z[0] = PetscRealPart(zt[0]); z[1] = PetscRealPart(zt[1]); z[2] = PetscRealPart(zt[2]); 446 } 447 break; 448 } 449 #else 450 ierr = DMPlexBasisTransformApply_Internal(dm, x, l2g, dim, y, z, ctx);CHKERRQ(ierr); 451 #endif 452 PetscFunctionReturn(0); 453 } 454 455 PetscErrorCode DMPlexBasisTransformApply_Internal(DM dm, const PetscReal x[], PetscBool l2g, PetscInt dim, const PetscScalar *y, PetscScalar *z, void *ctx) 456 { 457 const PetscScalar *A; 458 PetscErrorCode ierr; 459 460 PetscFunctionBeginHot; 461 ierr = (*dm->transformGetMatrix)(dm, x, l2g, &A, ctx);CHKERRQ(ierr); 462 switch (dim) { 463 case 2: DMPlex_Mult2D_Internal(A, 1, y, z);break; 464 case 3: DMPlex_Mult3D_Internal(A, 1, y, z);break; 465 } 466 PetscFunctionReturn(0); 467 } 468 469 static PetscErrorCode DMPlexBasisTransformField_Internal(DM dm, DM tdm, Vec tv, PetscInt p, PetscInt f, PetscBool l2g, PetscScalar *a) 470 { 471 PetscSection ts; 472 const PetscScalar *ta, *tva; 473 PetscInt dof; 474 PetscErrorCode ierr; 475 476 PetscFunctionBeginHot; 477 ierr = DMGetLocalSection(tdm, &ts);CHKERRQ(ierr); 478 ierr = PetscSectionGetFieldDof(ts, p, f, &dof);CHKERRQ(ierr); 479 ierr = VecGetArrayRead(tv, &ta);CHKERRQ(ierr); 480 ierr = DMPlexPointLocalFieldRead(tdm, p, f, ta, (void *) &tva);CHKERRQ(ierr); 481 if (l2g) { 482 switch (dof) { 483 case 4: DMPlex_Mult2D_Internal(tva, 1, a, a);break; 484 case 9: DMPlex_Mult3D_Internal(tva, 1, a, a);break; 485 } 486 } else { 487 switch (dof) { 488 case 4: DMPlex_MultTranspose2D_Internal(tva, 1, a, a);break; 489 case 9: DMPlex_MultTranspose3D_Internal(tva, 1, a, a);break; 490 } 491 } 492 ierr = VecRestoreArrayRead(tv, &ta);CHKERRQ(ierr); 493 PetscFunctionReturn(0); 494 } 495 496 static PetscErrorCode DMPlexBasisTransformFieldTensor_Internal(DM dm, DM tdm, Vec tv, PetscInt pf, PetscInt f, PetscInt pg, PetscInt g, PetscBool l2g, PetscInt lda, PetscScalar *a) 497 { 498 PetscSection s, ts; 499 const PetscScalar *ta, *tvaf, *tvag; 500 PetscInt fdof, gdof, fpdof, gpdof; 501 PetscErrorCode ierr; 502 503 PetscFunctionBeginHot; 504 ierr = DMGetLocalSection(dm, &s);CHKERRQ(ierr); 505 ierr = DMGetLocalSection(tdm, &ts);CHKERRQ(ierr); 506 ierr = PetscSectionGetFieldDof(s, pf, f, &fpdof);CHKERRQ(ierr); 507 ierr = PetscSectionGetFieldDof(s, pg, g, &gpdof);CHKERRQ(ierr); 508 ierr = PetscSectionGetFieldDof(ts, pf, f, &fdof);CHKERRQ(ierr); 509 ierr = PetscSectionGetFieldDof(ts, pg, g, &gdof);CHKERRQ(ierr); 510 ierr = VecGetArrayRead(tv, &ta);CHKERRQ(ierr); 511 ierr = DMPlexPointLocalFieldRead(tdm, pf, f, ta, (void *) &tvaf);CHKERRQ(ierr); 512 ierr = DMPlexPointLocalFieldRead(tdm, pg, g, ta, (void *) &tvag);CHKERRQ(ierr); 513 if (l2g) { 514 switch (fdof) { 515 case 4: DMPlex_MatMult2D_Internal(tvaf, gpdof, lda, a, a);break; 516 case 9: DMPlex_MatMult3D_Internal(tvaf, gpdof, lda, a, a);break; 517 } 518 switch (gdof) { 519 case 4: DMPlex_MatMultTransposeLeft2D_Internal(tvag, fpdof, lda, a, a);break; 520 case 9: DMPlex_MatMultTransposeLeft3D_Internal(tvag, fpdof, lda, a, a);break; 521 } 522 } else { 523 switch (fdof) { 524 case 4: DMPlex_MatMultTranspose2D_Internal(tvaf, gpdof, lda, a, a);break; 525 case 9: DMPlex_MatMultTranspose3D_Internal(tvaf, gpdof, lda, a, a);break; 526 } 527 switch (gdof) { 528 case 4: DMPlex_MatMultLeft2D_Internal(tvag, fpdof, lda, a, a);break; 529 case 9: DMPlex_MatMultLeft3D_Internal(tvag, fpdof, lda, a, a);break; 530 } 531 } 532 ierr = VecRestoreArrayRead(tv, &ta);CHKERRQ(ierr); 533 PetscFunctionReturn(0); 534 } 535 536 PetscErrorCode DMPlexBasisTransformPoint_Internal(DM dm, DM tdm, Vec tv, PetscInt p, PetscBool fieldActive[], PetscBool l2g, PetscScalar *a) 537 { 538 PetscSection s; 539 PetscSection clSection; 540 IS clPoints; 541 const PetscInt *clp; 542 PetscInt *points = NULL; 543 PetscInt Nf, f, Np, cp, dof, d = 0; 544 PetscErrorCode ierr; 545 546 PetscFunctionBegin; 547 ierr = DMGetLocalSection(dm, &s);CHKERRQ(ierr); 548 ierr = PetscSectionGetNumFields(s, &Nf);CHKERRQ(ierr); 549 ierr = DMPlexGetCompressedClosure(dm, s, p, &Np, &points, &clSection, &clPoints, &clp);CHKERRQ(ierr); 550 for (f = 0; f < Nf; ++f) { 551 for (cp = 0; cp < Np*2; cp += 2) { 552 ierr = PetscSectionGetFieldDof(s, points[cp], f, &dof);CHKERRQ(ierr); 553 if (!dof) continue; 554 if (fieldActive[f]) {ierr = DMPlexBasisTransformField_Internal(dm, tdm, tv, points[cp], f, l2g, &a[d]);CHKERRQ(ierr);} 555 d += dof; 556 } 557 } 558 ierr = DMPlexRestoreCompressedClosure(dm, s, p, &Np, &points, &clSection, &clPoints, &clp);CHKERRQ(ierr); 559 PetscFunctionReturn(0); 560 } 561 562 PetscErrorCode DMPlexBasisTransformPointTensor_Internal(DM dm, DM tdm, Vec tv, PetscInt p, PetscBool l2g, PetscInt lda, PetscScalar *a) 563 { 564 PetscSection s; 565 PetscSection clSection; 566 IS clPoints; 567 const PetscInt *clp; 568 PetscInt *points = NULL; 569 PetscInt Nf, f, g, Np, cpf, cpg, fdof, gdof, r, c = 0; 570 PetscErrorCode ierr; 571 572 PetscFunctionBegin; 573 ierr = DMGetLocalSection(dm, &s);CHKERRQ(ierr); 574 ierr = PetscSectionGetNumFields(s, &Nf);CHKERRQ(ierr); 575 ierr = DMPlexGetCompressedClosure(dm, s, p, &Np, &points, &clSection, &clPoints, &clp);CHKERRQ(ierr); 576 for (f = 0, r = 0; f < Nf; ++f) { 577 for (cpf = 0; cpf < Np*2; cpf += 2) { 578 ierr = PetscSectionGetFieldDof(s, points[cpf], f, &fdof);CHKERRQ(ierr); 579 for (g = 0, c = 0; g < Nf; ++g) { 580 for (cpg = 0; cpg < Np*2; cpg += 2) { 581 ierr = PetscSectionGetFieldDof(s, points[cpg], g, &gdof);CHKERRQ(ierr); 582 ierr = DMPlexBasisTransformFieldTensor_Internal(dm, tdm, tv, points[cpf], f, points[cpg], g, l2g, lda, &a[r*lda+c]);CHKERRQ(ierr); 583 c += gdof; 584 } 585 } 586 if (c != lda) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of columns %D should be %D", c, lda); 587 r += fdof; 588 } 589 } 590 if (r != lda) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of rows %D should be %D", c, lda); 591 ierr = DMPlexRestoreCompressedClosure(dm, s, p, &Np, &points, &clSection, &clPoints, &clp);CHKERRQ(ierr); 592 PetscFunctionReturn(0); 593 } 594 595 static PetscErrorCode DMPlexBasisTransform_Internal(DM dm, Vec lv, PetscBool l2g) 596 { 597 DM tdm; 598 Vec tv; 599 PetscSection ts, s; 600 const PetscScalar *ta; 601 PetscScalar *a, *va; 602 PetscInt pStart, pEnd, p, Nf, f; 603 PetscErrorCode ierr; 604 605 PetscFunctionBegin; 606 ierr = DMGetBasisTransformDM_Internal(dm, &tdm);CHKERRQ(ierr); 607 ierr = DMGetBasisTransformVec_Internal(dm, &tv);CHKERRQ(ierr); 608 ierr = DMGetLocalSection(tdm, &ts);CHKERRQ(ierr); 609 ierr = DMGetLocalSection(dm, &s);CHKERRQ(ierr); 610 ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr); 611 ierr = PetscSectionGetNumFields(s, &Nf);CHKERRQ(ierr); 612 ierr = VecGetArray(lv, &a);CHKERRQ(ierr); 613 ierr = VecGetArrayRead(tv, &ta);CHKERRQ(ierr); 614 for (p = pStart; p < pEnd; ++p) { 615 for (f = 0; f < Nf; ++f) { 616 ierr = DMPlexPointLocalFieldRef(dm, p, f, a, (void *) &va);CHKERRQ(ierr); 617 ierr = DMPlexBasisTransformField_Internal(dm, tdm, tv, p, f, l2g, va);CHKERRQ(ierr); 618 } 619 } 620 ierr = VecRestoreArray(lv, &a);CHKERRQ(ierr); 621 ierr = VecRestoreArrayRead(tv, &ta);CHKERRQ(ierr); 622 PetscFunctionReturn(0); 623 } 624 625 /*@ 626 DMPlexGlobalToLocalBasis - Transform the values in the given local vector from the global basis to the local basis 627 628 Input Parameters: 629 + dm - The DM 630 - lv - A local vector with values in the global basis 631 632 Output Parameters: 633 . lv - A local vector with values in the local basis 634 635 Note: This method is only intended to be called inside DMGlobalToLocal(). It is unlikely that a user will have a local vector full of coefficients for the global basis unless they are reimplementing GlobalToLocal. 636 637 Level: developer 638 639 .seealso: DMPlexLocalToGlobalBasis(), DMGetLocalSection() 640 @*/ 641 PetscErrorCode DMPlexGlobalToLocalBasis(DM dm, Vec lv) 642 { 643 PetscErrorCode ierr; 644 645 PetscFunctionBegin; 646 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 647 PetscValidHeaderSpecific(lv, VEC_CLASSID, 2); 648 ierr = DMPlexBasisTransform_Internal(dm, lv, PETSC_FALSE);CHKERRQ(ierr); 649 PetscFunctionReturn(0); 650 } 651 652 /*@ 653 DMPlexLocalToGlobalBasis - Transform the values in the given local vector from the local basis to the global basis 654 655 Input Parameters: 656 + dm - The DM 657 - lv - A local vector with values in the local basis 658 659 Output Parameters: 660 . lv - A local vector with values in the global basis 661 662 Note: This method is only intended to be called inside DMGlobalToLocal(). It is unlikely that a user would want a local vector full of coefficients for the global basis unless they are reimplementing GlobalToLocal. 663 664 Level: developer 665 666 .seealso: DMPlexGlobalToLocalBasis(), DMGetLocalSection() 667 @*/ 668 PetscErrorCode DMPlexLocalToGlobalBasis(DM dm, Vec lv) 669 { 670 PetscErrorCode ierr; 671 672 PetscFunctionBegin; 673 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 674 PetscValidHeaderSpecific(lv, VEC_CLASSID, 2); 675 ierr = DMPlexBasisTransform_Internal(dm, lv, PETSC_TRUE);CHKERRQ(ierr); 676 PetscFunctionReturn(0); 677 } 678 679 /*@ 680 DMPlexCreateBasisRotation - Create an internal transformation from the global basis, used to specify boundary conditions 681 and global solutions, to a local basis, appropriate for discretization integrals and assembly. 682 683 Input Parameters: 684 + dm - The DM 685 . alpha - The first Euler angle, and in 2D the only one 686 . beta - The second Euler angle 687 . gamma - The third Euler angle 688 689 Note: Following https://en.wikipedia.org/wiki/Euler_angles, we will specify Euler angles by extrinsic rotations, meaning that 690 we rotate with respect to a fixed initial coordinate system, the local basis (x-y-z). The global basis (X-Y-Z) is reached as follows: 691 $ The XYZ system rotates about the z axis by alpha. The X axis is now at angle alpha with respect to the x axis. 692 $ The XYZ system rotates again about the x axis by beta. The Z axis is now at angle beta with respect to the z axis. 693 $ The XYZ system rotates a third time about the z axis by gamma. 694 695 Level: developer 696 697 .seealso: DMPlexGlobalToLocalBasis(), DMPlexLocalToGlobalBasis() 698 @*/ 699 PetscErrorCode DMPlexCreateBasisRotation(DM dm, PetscReal alpha, PetscReal beta, PetscReal gamma) 700 { 701 RotCtx *rc; 702 PetscInt cdim; 703 PetscErrorCode ierr; 704 705 ierr = DMGetCoordinateDim(dm, &cdim);CHKERRQ(ierr); 706 ierr = PetscMalloc1(1, &rc);CHKERRQ(ierr); 707 dm->transformCtx = rc; 708 dm->transformSetUp = DMPlexBasisTransformSetUp_Rotation_Internal; 709 dm->transformDestroy = DMPlexBasisTransformDestroy_Rotation_Internal; 710 dm->transformGetMatrix = DMPlexBasisTransformGetMatrix_Rotation_Internal; 711 rc->dim = cdim; 712 rc->alpha = alpha; 713 rc->beta = beta; 714 rc->gamma = gamma; 715 ierr = (*dm->transformSetUp)(dm, dm->transformCtx);CHKERRQ(ierr); 716 ierr = DMConstructBasisTransform_Internal(dm);CHKERRQ(ierr); 717 PetscFunctionReturn(0); 718 } 719 720 /*@C 721 DMPlexInsertBoundaryValuesEssential - Insert boundary values into a local vector 722 723 Input Parameters: 724 + dm - The DM, with a PetscDS that matches the problem being constrained 725 . time - The time 726 . field - The field to constrain 727 . Nc - The number of constrained field components, or 0 for all components 728 . comps - An array of constrained component numbers, or NULL for all components 729 . label - The DMLabel defining constrained points 730 . numids - The number of DMLabel ids for constrained points 731 . ids - An array of ids for constrained points 732 . func - A pointwise function giving boundary values 733 - ctx - An optional user context for bcFunc 734 735 Output Parameter: 736 . locX - A local vector to receives the boundary values 737 738 Level: developer 739 740 .seealso: DMPlexInsertBoundaryValuesEssentialField(), DMAddBoundary() 741 @*/ 742 PetscErrorCode DMPlexInsertBoundaryValuesEssential(DM dm, PetscReal time, PetscInt field, PetscInt Nc, const PetscInt comps[], DMLabel label, PetscInt numids, const PetscInt ids[], PetscErrorCode (*func)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void *ctx, Vec locX) 743 { 744 PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx); 745 void **ctxs; 746 PetscInt numFields; 747 PetscErrorCode ierr; 748 749 PetscFunctionBegin; 750 ierr = DMGetNumFields(dm, &numFields);CHKERRQ(ierr); 751 ierr = PetscCalloc2(numFields,&funcs,numFields,&ctxs);CHKERRQ(ierr); 752 funcs[field] = func; 753 ctxs[field] = ctx; 754 ierr = DMProjectFunctionLabelLocal(dm, time, label, numids, ids, Nc, comps, funcs, ctxs, INSERT_BC_VALUES, locX);CHKERRQ(ierr); 755 ierr = PetscFree2(funcs,ctxs);CHKERRQ(ierr); 756 PetscFunctionReturn(0); 757 } 758 759 /*@C 760 DMPlexInsertBoundaryValuesEssentialField - Insert boundary values into a local vector 761 762 Input Parameters: 763 + dm - The DM, with a PetscDS that matches the problem being constrained 764 . time - The time 765 . locU - A local vector with the input solution values 766 . field - The field to constrain 767 . Nc - The number of constrained field components, or 0 for all components 768 . comps - An array of constrained component numbers, or NULL for all components 769 . label - The DMLabel defining constrained points 770 . numids - The number of DMLabel ids for constrained points 771 . ids - An array of ids for constrained points 772 . func - A pointwise function giving boundary values 773 - ctx - An optional user context for bcFunc 774 775 Output Parameter: 776 . locX - A local vector to receives the boundary values 777 778 Level: developer 779 780 .seealso: DMPlexInsertBoundaryValuesEssential(), DMAddBoundary() 781 @*/ 782 PetscErrorCode DMPlexInsertBoundaryValuesEssentialField(DM dm, PetscReal time, Vec locU, PetscInt field, PetscInt Nc, const PetscInt comps[], DMLabel label, PetscInt numids, const PetscInt ids[], 783 void (*func)(PetscInt, PetscInt, PetscInt, 784 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 785 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 786 PetscReal, const PetscReal[], PetscInt, const PetscScalar[], 787 PetscScalar[]), 788 void *ctx, Vec locX) 789 { 790 void (**funcs)(PetscInt, PetscInt, PetscInt, 791 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 792 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 793 PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]); 794 void **ctxs; 795 PetscInt numFields; 796 PetscErrorCode ierr; 797 798 PetscFunctionBegin; 799 ierr = DMGetNumFields(dm, &numFields);CHKERRQ(ierr); 800 ierr = PetscCalloc2(numFields,&funcs,numFields,&ctxs);CHKERRQ(ierr); 801 funcs[field] = func; 802 ctxs[field] = ctx; 803 ierr = DMProjectFieldLabelLocal(dm, time, label, numids, ids, Nc, comps, locU, funcs, INSERT_BC_VALUES, locX);CHKERRQ(ierr); 804 ierr = PetscFree2(funcs,ctxs);CHKERRQ(ierr); 805 PetscFunctionReturn(0); 806 } 807 808 /*@C 809 DMPlexInsertBoundaryValuesRiemann - Insert boundary values into a local vector 810 811 Input Parameters: 812 + dm - The DM, with a PetscDS that matches the problem being constrained 813 . time - The time 814 . faceGeometry - A vector with the FVM face geometry information 815 . cellGeometry - A vector with the FVM cell geometry information 816 . Grad - A vector with the FVM cell gradient information 817 . field - The field to constrain 818 . Nc - The number of constrained field components, or 0 for all components 819 . comps - An array of constrained component numbers, or NULL for all components 820 . label - The DMLabel defining constrained points 821 . numids - The number of DMLabel ids for constrained points 822 . ids - An array of ids for constrained points 823 . func - A pointwise function giving boundary values 824 - ctx - An optional user context for bcFunc 825 826 Output Parameter: 827 . locX - A local vector to receives the boundary values 828 829 Note: This implementation currently ignores the numcomps/comps argument from DMAddBoundary() 830 831 Level: developer 832 833 .seealso: DMPlexInsertBoundaryValuesEssential(), DMPlexInsertBoundaryValuesEssentialField(), DMAddBoundary() 834 @*/ 835 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[], 836 PetscErrorCode (*func)(PetscReal,const PetscReal*,const PetscReal*,const PetscScalar*,PetscScalar*,void*), void *ctx, Vec locX) 837 { 838 PetscDS prob; 839 PetscSF sf; 840 DM dmFace, dmCell, dmGrad; 841 const PetscScalar *facegeom, *cellgeom = NULL, *grad; 842 const PetscInt *leaves; 843 PetscScalar *x, *fx; 844 PetscInt dim, nleaves, loc, fStart, fEnd, pdim, i; 845 PetscErrorCode ierr, ierru = 0; 846 847 PetscFunctionBegin; 848 ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr); 849 ierr = PetscSFGetGraph(sf, NULL, &nleaves, &leaves, NULL);CHKERRQ(ierr); 850 nleaves = PetscMax(0, nleaves); 851 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 852 ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr); 853 ierr = DMGetDS(dm, &prob);CHKERRQ(ierr); 854 ierr = VecGetDM(faceGeometry, &dmFace);CHKERRQ(ierr); 855 ierr = VecGetArrayRead(faceGeometry, &facegeom);CHKERRQ(ierr); 856 if (cellGeometry) { 857 ierr = VecGetDM(cellGeometry, &dmCell);CHKERRQ(ierr); 858 ierr = VecGetArrayRead(cellGeometry, &cellgeom);CHKERRQ(ierr); 859 } 860 if (Grad) { 861 PetscFV fv; 862 863 ierr = PetscDSGetDiscretization(prob, field, (PetscObject *) &fv);CHKERRQ(ierr); 864 ierr = VecGetDM(Grad, &dmGrad);CHKERRQ(ierr); 865 ierr = VecGetArrayRead(Grad, &grad);CHKERRQ(ierr); 866 ierr = PetscFVGetNumComponents(fv, &pdim);CHKERRQ(ierr); 867 ierr = DMGetWorkArray(dm, pdim, MPIU_SCALAR, &fx);CHKERRQ(ierr); 868 } 869 ierr = VecGetArray(locX, &x);CHKERRQ(ierr); 870 for (i = 0; i < numids; ++i) { 871 IS faceIS; 872 const PetscInt *faces; 873 PetscInt numFaces, f; 874 875 ierr = DMLabelGetStratumIS(label, ids[i], &faceIS);CHKERRQ(ierr); 876 if (!faceIS) continue; /* No points with that id on this process */ 877 ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr); 878 ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr); 879 for (f = 0; f < numFaces; ++f) { 880 const PetscInt face = faces[f], *cells; 881 PetscFVFaceGeom *fg; 882 883 if ((face < fStart) || (face >= fEnd)) continue; /* Refinement adds non-faces to labels */ 884 ierr = PetscFindInt(face, nleaves, (PetscInt *) leaves, &loc);CHKERRQ(ierr); 885 if (loc >= 0) continue; 886 ierr = DMPlexPointLocalRead(dmFace, face, facegeom, &fg);CHKERRQ(ierr); 887 ierr = DMPlexGetSupport(dm, face, &cells);CHKERRQ(ierr); 888 if (Grad) { 889 PetscFVCellGeom *cg; 890 PetscScalar *cx, *cgrad; 891 PetscScalar *xG; 892 PetscReal dx[3]; 893 PetscInt d; 894 895 ierr = DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cg);CHKERRQ(ierr); 896 ierr = DMPlexPointLocalRead(dm, cells[0], x, &cx);CHKERRQ(ierr); 897 ierr = DMPlexPointLocalRead(dmGrad, cells[0], grad, &cgrad);CHKERRQ(ierr); 898 ierr = DMPlexPointLocalFieldRef(dm, cells[1], field, x, &xG);CHKERRQ(ierr); 899 DMPlex_WaxpyD_Internal(dim, -1, cg->centroid, fg->centroid, dx); 900 for (d = 0; d < pdim; ++d) fx[d] = cx[d] + DMPlex_DotD_Internal(dim, &cgrad[d*dim], dx); 901 ierru = (*func)(time, fg->centroid, fg->normal, fx, xG, ctx); 902 if (ierru) { 903 ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr); 904 ierr = ISDestroy(&faceIS);CHKERRQ(ierr); 905 goto cleanup; 906 } 907 } else { 908 PetscScalar *xI; 909 PetscScalar *xG; 910 911 ierr = DMPlexPointLocalRead(dm, cells[0], x, &xI);CHKERRQ(ierr); 912 ierr = DMPlexPointLocalFieldRef(dm, cells[1], field, x, &xG);CHKERRQ(ierr); 913 ierru = (*func)(time, fg->centroid, fg->normal, xI, xG, ctx); 914 if (ierru) { 915 ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr); 916 ierr = ISDestroy(&faceIS);CHKERRQ(ierr); 917 goto cleanup; 918 } 919 } 920 } 921 ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr); 922 ierr = ISDestroy(&faceIS);CHKERRQ(ierr); 923 } 924 cleanup: 925 ierr = VecRestoreArray(locX, &x);CHKERRQ(ierr); 926 if (Grad) { 927 ierr = DMRestoreWorkArray(dm, pdim, MPIU_SCALAR, &fx);CHKERRQ(ierr); 928 ierr = VecRestoreArrayRead(Grad, &grad);CHKERRQ(ierr); 929 } 930 if (cellGeometry) {ierr = VecRestoreArrayRead(cellGeometry, &cellgeom);CHKERRQ(ierr);} 931 ierr = VecRestoreArrayRead(faceGeometry, &facegeom);CHKERRQ(ierr); 932 CHKERRQ(ierru); 933 PetscFunctionReturn(0); 934 } 935 936 PetscErrorCode DMPlexInsertBoundaryValues_Plex(DM dm, PetscBool insertEssential, Vec locX, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM) 937 { 938 PetscDS prob; 939 PetscInt numBd, b; 940 PetscErrorCode ierr; 941 942 PetscFunctionBegin; 943 ierr = DMGetDS(dm, &prob);CHKERRQ(ierr); 944 ierr = PetscDSGetNumBoundary(prob, &numBd);CHKERRQ(ierr); 945 for (b = 0; b < numBd; ++b) { 946 DMBoundaryConditionType type; 947 const char *name, *labelname; 948 DMLabel label; 949 PetscInt field, Nc; 950 const PetscInt *comps; 951 PetscObject obj; 952 PetscClassId id; 953 void (*func)(void); 954 PetscInt numids; 955 const PetscInt *ids; 956 void *ctx; 957 958 ierr = DMGetBoundary(dm, b, &type, &name, &labelname, &field, &Nc, &comps, &func, &numids, &ids, &ctx);CHKERRQ(ierr); 959 if (insertEssential != (type & DM_BC_ESSENTIAL)) continue; 960 ierr = DMGetLabel(dm, labelname, &label);CHKERRQ(ierr); 961 if (!label) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONGSTATE, "Label %s for boundary condition %s does not exist in the DM", labelname, name); 962 ierr = DMGetField(dm, field, NULL, &obj);CHKERRQ(ierr); 963 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 964 if (id == PETSCFE_CLASSID) { 965 switch (type) { 966 /* for FEM, there is no insertion to be done for non-essential boundary conditions */ 967 case DM_BC_ESSENTIAL: 968 ierr = DMPlexLabelAddCells(dm,label);CHKERRQ(ierr); 969 ierr = DMPlexInsertBoundaryValuesEssential(dm, time, field, Nc, comps, label, numids, ids, (PetscErrorCode (*)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *)) func, ctx, locX);CHKERRQ(ierr); 970 ierr = DMPlexLabelClearCells(dm,label);CHKERRQ(ierr); 971 break; 972 case DM_BC_ESSENTIAL_FIELD: 973 ierr = DMPlexLabelAddCells(dm,label);CHKERRQ(ierr); 974 ierr = DMPlexInsertBoundaryValuesEssentialField(dm, time, locX, field, Nc, comps, label, numids, ids, 975 (void (*)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 976 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 977 PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[])) func, ctx, locX);CHKERRQ(ierr); 978 ierr = DMPlexLabelClearCells(dm,label);CHKERRQ(ierr); 979 break; 980 default: break; 981 } 982 } else if (id == PETSCFV_CLASSID) { 983 if (!faceGeomFVM) continue; 984 ierr = DMPlexInsertBoundaryValuesRiemann(dm, time, faceGeomFVM, cellGeomFVM, gradFVM, field, Nc, comps, label, numids, ids, 985 (PetscErrorCode (*)(PetscReal,const PetscReal*,const PetscReal*,const PetscScalar*,PetscScalar*,void*)) func, ctx, locX);CHKERRQ(ierr); 986 } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", field); 987 } 988 PetscFunctionReturn(0); 989 } 990 991 /*@ 992 DMPlexInsertBoundaryValues - Puts coefficients which represent boundary values into the local solution vector 993 994 Input Parameters: 995 + dm - The DM 996 . insertEssential - Should I insert essential (e.g. Dirichlet) or inessential (e.g. Neumann) boundary conditions 997 . time - The time 998 . faceGeomFVM - Face geometry data for FV discretizations 999 . cellGeomFVM - Cell geometry data for FV discretizations 1000 - gradFVM - Gradient reconstruction data for FV discretizations 1001 1002 Output Parameters: 1003 . locX - Solution updated with boundary values 1004 1005 Level: developer 1006 1007 .seealso: DMProjectFunctionLabelLocal() 1008 @*/ 1009 PetscErrorCode DMPlexInsertBoundaryValues(DM dm, PetscBool insertEssential, Vec locX, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM) 1010 { 1011 PetscErrorCode ierr; 1012 1013 PetscFunctionBegin; 1014 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1015 PetscValidHeaderSpecific(locX, VEC_CLASSID, 2); 1016 if (faceGeomFVM) {PetscValidHeaderSpecific(faceGeomFVM, VEC_CLASSID, 4);} 1017 if (cellGeomFVM) {PetscValidHeaderSpecific(cellGeomFVM, VEC_CLASSID, 5);} 1018 if (gradFVM) {PetscValidHeaderSpecific(gradFVM, VEC_CLASSID, 6);} 1019 ierr = PetscTryMethod(dm,"DMPlexInsertBoundaryValues_C",(DM,PetscBool,Vec,PetscReal,Vec,Vec,Vec),(dm,insertEssential,locX,time,faceGeomFVM,cellGeomFVM,gradFVM));CHKERRQ(ierr); 1020 PetscFunctionReturn(0); 1021 } 1022 1023 PetscErrorCode DMComputeL2Diff_Plex(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff) 1024 { 1025 Vec localX; 1026 PetscErrorCode ierr; 1027 1028 PetscFunctionBegin; 1029 ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr); 1030 ierr = DMPlexInsertBoundaryValues(dm, PETSC_TRUE, localX, time, NULL, NULL, NULL);CHKERRQ(ierr); 1031 ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr); 1032 ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr); 1033 ierr = DMPlexComputeL2DiffLocal(dm, time, funcs, ctxs, localX, diff);CHKERRQ(ierr); 1034 ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr); 1035 PetscFunctionReturn(0); 1036 } 1037 1038 /*@C 1039 DMComputeL2DiffLocal - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h. 1040 1041 Collective on dm 1042 1043 Input Parameters: 1044 + dm - The DM 1045 . time - The time 1046 . funcs - The functions to evaluate for each field component 1047 . ctxs - Optional array of contexts to pass to each function, or NULL. 1048 - localX - The coefficient vector u_h, a local vector 1049 1050 Output Parameter: 1051 . diff - The diff ||u - u_h||_2 1052 1053 Level: developer 1054 1055 .seealso: DMProjectFunction(), DMComputeL2FieldDiff(), DMComputeL2GradientDiff() 1056 @*/ 1057 PetscErrorCode DMPlexComputeL2DiffLocal(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec localX, PetscReal *diff) 1058 { 1059 const PetscInt debug = ((DM_Plex*)dm->data)->printL2; 1060 DM tdm; 1061 Vec tv; 1062 PetscSection section; 1063 PetscQuadrature quad; 1064 PetscFEGeom fegeom; 1065 PetscScalar *funcVal, *interpolant; 1066 PetscReal *coords, *gcoords; 1067 PetscReal localDiff = 0.0; 1068 const PetscReal *quadWeights; 1069 PetscInt dim, coordDim, numFields, numComponents = 0, qNc, Nq, cellHeight, cStart, cEnd, cEndInterior, c, field, fieldOffset; 1070 PetscBool transform; 1071 PetscErrorCode ierr; 1072 1073 PetscFunctionBegin; 1074 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 1075 ierr = DMGetCoordinateDim(dm, &coordDim);CHKERRQ(ierr); 1076 fegeom.dimEmbed = coordDim; 1077 ierr = DMGetLocalSection(dm, §ion);CHKERRQ(ierr); 1078 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 1079 ierr = DMGetBasisTransformDM_Internal(dm, &tdm);CHKERRQ(ierr); 1080 ierr = DMGetBasisTransformVec_Internal(dm, &tv);CHKERRQ(ierr); 1081 ierr = DMHasBasisTransform(dm, &transform);CHKERRQ(ierr); 1082 for (field = 0; field < numFields; ++field) { 1083 PetscObject obj; 1084 PetscClassId id; 1085 PetscInt Nc; 1086 1087 ierr = DMGetField(dm, field, NULL, &obj);CHKERRQ(ierr); 1088 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 1089 if (id == PETSCFE_CLASSID) { 1090 PetscFE fe = (PetscFE) obj; 1091 1092 ierr = PetscFEGetQuadrature(fe, &quad);CHKERRQ(ierr); 1093 ierr = PetscFEGetNumComponents(fe, &Nc);CHKERRQ(ierr); 1094 } else if (id == PETSCFV_CLASSID) { 1095 PetscFV fv = (PetscFV) obj; 1096 1097 ierr = PetscFVGetQuadrature(fv, &quad);CHKERRQ(ierr); 1098 ierr = PetscFVGetNumComponents(fv, &Nc);CHKERRQ(ierr); 1099 } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", field); 1100 numComponents += Nc; 1101 } 1102 ierr = PetscQuadratureGetData(quad, NULL, &qNc, &Nq, NULL, &quadWeights);CHKERRQ(ierr); 1103 if ((qNc != 1) && (qNc != numComponents)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_SIZ, "Quadrature components %D != %D field components", qNc, numComponents); 1104 ierr = PetscMalloc6(numComponents,&funcVal,numComponents,&interpolant,coordDim*Nq,&coords,Nq,&fegeom.detJ,coordDim*coordDim*Nq,&fegeom.J,coordDim*coordDim*Nq,&fegeom.invJ);CHKERRQ(ierr); 1105 ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr); 1106 ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr); 1107 ierr = DMPlexGetGhostCellStratum(dm, &cEndInterior, NULL);CHKERRQ(ierr); 1108 cEnd = cEndInterior < 0 ? cEnd : cEndInterior; 1109 ierr = DMPlexGetHybridBounds(dm, &cEndInterior, NULL, NULL, NULL);CHKERRQ(ierr); 1110 cEnd = cEndInterior < 0 ? cEnd : cEndInterior; 1111 for (c = cStart; c < cEnd; ++c) { 1112 PetscScalar *x = NULL; 1113 PetscReal elemDiff = 0.0; 1114 PetscInt qc = 0; 1115 1116 ierr = DMPlexComputeCellGeometryFEM(dm, c, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ);CHKERRQ(ierr); 1117 ierr = DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr); 1118 1119 for (field = 0, fieldOffset = 0; field < numFields; ++field) { 1120 PetscObject obj; 1121 PetscClassId id; 1122 void * const ctx = ctxs ? ctxs[field] : NULL; 1123 PetscInt Nb, Nc, q, fc; 1124 1125 ierr = DMGetField(dm, field, NULL, &obj);CHKERRQ(ierr); 1126 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 1127 if (id == PETSCFE_CLASSID) {ierr = PetscFEGetNumComponents((PetscFE) obj, &Nc);CHKERRQ(ierr);ierr = PetscFEGetDimension((PetscFE) obj, &Nb);CHKERRQ(ierr);} 1128 else if (id == PETSCFV_CLASSID) {ierr = PetscFVGetNumComponents((PetscFV) obj, &Nc);CHKERRQ(ierr);Nb = 1;} 1129 else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", field); 1130 if (debug) { 1131 char title[1024]; 1132 ierr = PetscSNPrintf(title, 1023, "Solution for Field %D", field);CHKERRQ(ierr); 1133 ierr = DMPrintCellVector(c, title, Nb, &x[fieldOffset]);CHKERRQ(ierr); 1134 } 1135 for (q = 0; q < Nq; ++q) { 1136 PetscFEGeom qgeom; 1137 1138 qgeom.dimEmbed = fegeom.dimEmbed; 1139 qgeom.J = &fegeom.J[q*coordDim*coordDim]; 1140 qgeom.invJ = &fegeom.invJ[q*coordDim*coordDim]; 1141 qgeom.detJ = &fegeom.detJ[q]; 1142 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); 1143 if (transform) { 1144 gcoords = &coords[coordDim*Nq]; 1145 ierr = DMPlexBasisTransformApplyReal_Internal(dm, &coords[coordDim*q], PETSC_TRUE, coordDim, &coords[coordDim*q], gcoords, dm->transformCtx);CHKERRQ(ierr); 1146 } else { 1147 gcoords = &coords[coordDim*q]; 1148 } 1149 ierr = (*funcs[field])(coordDim, time, gcoords, Nc, funcVal, ctx); 1150 if (ierr) { 1151 PetscErrorCode ierr2; 1152 ierr2 = DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr2); 1153 ierr2 = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr2); 1154 ierr2 = PetscFree6(funcVal,interpolant,coords,fegeom.detJ,fegeom.J,fegeom.invJ);CHKERRQ(ierr2); 1155 CHKERRQ(ierr); 1156 } 1157 if (transform) {ierr = DMPlexBasisTransformApply_Internal(dm, &coords[coordDim*q], PETSC_FALSE, Nc, funcVal, funcVal, dm->transformCtx);CHKERRQ(ierr);} 1158 if (id == PETSCFE_CLASSID) {ierr = PetscFEInterpolate_Static((PetscFE) obj, &x[fieldOffset], &qgeom, q, interpolant);CHKERRQ(ierr);} 1159 else if (id == PETSCFV_CLASSID) {ierr = PetscFVInterpolate_Static((PetscFV) obj, &x[fieldOffset], q, interpolant);CHKERRQ(ierr);} 1160 else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", field); 1161 for (fc = 0; fc < Nc; ++fc) { 1162 const PetscReal wt = quadWeights[q*qNc+(qNc == 1 ? 0 : qc+fc)]; 1163 if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, " elem %D field %D,%D diff %g\n", c, field, fc, (double)(PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc]))*wt*fegeom.detJ[q]));CHKERRQ(ierr);} 1164 elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc]))*wt*fegeom.detJ[q]; 1165 } 1166 } 1167 fieldOffset += Nb; 1168 qc += Nc; 1169 } 1170 ierr = DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr); 1171 if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, " elem %D diff %g\n", c, (double)elemDiff);CHKERRQ(ierr);} 1172 localDiff += elemDiff; 1173 } 1174 ierr = PetscFree6(funcVal,interpolant,coords,fegeom.detJ,fegeom.J,fegeom.invJ);CHKERRQ(ierr); 1175 ierr = MPIU_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr); 1176 *diff = PetscSqrtReal(*diff); 1177 PetscFunctionReturn(0); 1178 } 1179 1180 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) 1181 { 1182 const PetscInt debug = ((DM_Plex*)dm->data)->printL2; 1183 DM tdm; 1184 PetscSection section; 1185 PetscQuadrature quad; 1186 Vec localX, tv; 1187 PetscScalar *funcVal, *interpolant; 1188 const PetscReal *quadWeights; 1189 PetscFEGeom fegeom; 1190 PetscReal *coords, *gcoords; 1191 PetscReal localDiff = 0.0; 1192 PetscInt dim, coordDim, qNc = 0, Nq = 0, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset; 1193 PetscBool transform; 1194 PetscErrorCode ierr; 1195 1196 PetscFunctionBegin; 1197 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 1198 ierr = DMGetCoordinateDim(dm, &coordDim);CHKERRQ(ierr); 1199 fegeom.dimEmbed = coordDim; 1200 ierr = DMGetLocalSection(dm, §ion);CHKERRQ(ierr); 1201 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 1202 ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr); 1203 ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr); 1204 ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr); 1205 ierr = DMGetBasisTransformDM_Internal(dm, &tdm);CHKERRQ(ierr); 1206 ierr = DMGetBasisTransformVec_Internal(dm, &tv);CHKERRQ(ierr); 1207 ierr = DMHasBasisTransform(dm, &transform);CHKERRQ(ierr); 1208 for (field = 0; field < numFields; ++field) { 1209 PetscFE fe; 1210 PetscInt Nc; 1211 1212 ierr = DMGetField(dm, field, NULL, (PetscObject *) &fe);CHKERRQ(ierr); 1213 ierr = PetscFEGetQuadrature(fe, &quad);CHKERRQ(ierr); 1214 ierr = PetscFEGetNumComponents(fe, &Nc);CHKERRQ(ierr); 1215 numComponents += Nc; 1216 } 1217 ierr = PetscQuadratureGetData(quad, NULL, &qNc, &Nq, NULL, &quadWeights);CHKERRQ(ierr); 1218 if ((qNc != 1) && (qNc != numComponents)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_SIZ, "Quadrature components %D != %D field components", qNc, numComponents); 1219 /* ierr = DMProjectFunctionLocal(dm, fe, funcs, INSERT_BC_VALUES, localX);CHKERRQ(ierr); */ 1220 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); 1221 ierr = DMPlexGetInteriorCellStratum(dm, &cStart, &cEnd);CHKERRQ(ierr); 1222 for (c = cStart; c < cEnd; ++c) { 1223 PetscScalar *x = NULL; 1224 PetscReal elemDiff = 0.0; 1225 PetscInt qc = 0; 1226 1227 ierr = DMPlexComputeCellGeometryFEM(dm, c, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ);CHKERRQ(ierr); 1228 ierr = DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr); 1229 1230 for (field = 0, fieldOffset = 0; field < numFields; ++field) { 1231 PetscFE fe; 1232 void * const ctx = ctxs ? ctxs[field] : NULL; 1233 PetscInt Nb, Nc, q, fc; 1234 1235 ierr = DMGetField(dm, field, NULL, (PetscObject *) &fe);CHKERRQ(ierr); 1236 ierr = PetscFEGetDimension(fe, &Nb);CHKERRQ(ierr); 1237 ierr = PetscFEGetNumComponents(fe, &Nc);CHKERRQ(ierr); 1238 if (debug) { 1239 char title[1024]; 1240 ierr = PetscSNPrintf(title, 1023, "Solution for Field %D", field);CHKERRQ(ierr); 1241 ierr = DMPrintCellVector(c, title, Nb, &x[fieldOffset]);CHKERRQ(ierr); 1242 } 1243 for (q = 0; q < Nq; ++q) { 1244 PetscFEGeom qgeom; 1245 1246 qgeom.dimEmbed = fegeom.dimEmbed; 1247 qgeom.J = &fegeom.J[q*coordDim*coordDim]; 1248 qgeom.invJ = &fegeom.invJ[q*coordDim*coordDim]; 1249 qgeom.detJ = &fegeom.detJ[q]; 1250 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); 1251 if (transform) { 1252 gcoords = &coords[coordDim*Nq]; 1253 ierr = DMPlexBasisTransformApplyReal_Internal(dm, &coords[coordDim*q], PETSC_TRUE, coordDim, &coords[coordDim*q], gcoords, dm->transformCtx);CHKERRQ(ierr); 1254 } else { 1255 gcoords = &coords[coordDim*q]; 1256 } 1257 ierr = (*funcs[field])(coordDim, time, gcoords, n, Nc, funcVal, ctx); 1258 if (ierr) { 1259 PetscErrorCode ierr2; 1260 ierr2 = DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr2); 1261 ierr2 = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr2); 1262 ierr2 = PetscFree6(funcVal,coords,fegeom.J,fegeom.invJ,interpolant,fegeom.detJ);CHKERRQ(ierr2); 1263 CHKERRQ(ierr); 1264 } 1265 if (transform) {ierr = DMPlexBasisTransformApply_Internal(dm, &coords[coordDim*q], PETSC_FALSE, Nc, funcVal, funcVal, dm->transformCtx);CHKERRQ(ierr);} 1266 ierr = PetscFEInterpolateGradient_Static(fe, &x[fieldOffset], &qgeom, q, interpolant);CHKERRQ(ierr); 1267 /* Overwrite with the dot product if the normal is given */ 1268 if (n) { 1269 for (fc = 0; fc < Nc; ++fc) { 1270 PetscScalar sum = 0.0; 1271 PetscInt d; 1272 for (d = 0; d < dim; ++d) sum += interpolant[fc*dim+d]*n[d]; 1273 interpolant[fc] = sum; 1274 } 1275 } 1276 for (fc = 0; fc < Nc; ++fc) { 1277 const PetscReal wt = quadWeights[q*qNc+(qNc == 1 ? 0 : qc+fc)]; 1278 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);} 1279 elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc]))*wt*fegeom.detJ[q]; 1280 } 1281 } 1282 fieldOffset += Nb; 1283 qc += Nc; 1284 } 1285 ierr = DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr); 1286 if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, " elem %D diff %g\n", c, (double)elemDiff);CHKERRQ(ierr);} 1287 localDiff += elemDiff; 1288 } 1289 ierr = PetscFree6(funcVal,coords,fegeom.J,fegeom.invJ,interpolant,fegeom.detJ);CHKERRQ(ierr); 1290 ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr); 1291 ierr = MPIU_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr); 1292 *diff = PetscSqrtReal(*diff); 1293 PetscFunctionReturn(0); 1294 } 1295 1296 PetscErrorCode DMComputeL2FieldDiff_Plex(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff) 1297 { 1298 const PetscInt debug = ((DM_Plex*)dm->data)->printL2; 1299 DM tdm; 1300 PetscSection section; 1301 PetscQuadrature quad; 1302 Vec localX, tv; 1303 PetscFEGeom fegeom; 1304 PetscScalar *funcVal, *interpolant; 1305 PetscReal *coords, *gcoords; 1306 PetscReal *localDiff; 1307 const PetscReal *quadPoints, *quadWeights; 1308 PetscInt dim, coordDim, numFields, numComponents = 0, qNc, Nq, cStart, cEnd, c, field, fieldOffset; 1309 PetscBool transform; 1310 PetscErrorCode ierr; 1311 1312 PetscFunctionBegin; 1313 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 1314 ierr = DMGetCoordinateDim(dm, &coordDim);CHKERRQ(ierr); 1315 ierr = DMGetLocalSection(dm, §ion);CHKERRQ(ierr); 1316 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 1317 ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr); 1318 ierr = VecSet(localX, 0.0);CHKERRQ(ierr); 1319 ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr); 1320 ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr); 1321 ierr = DMProjectFunctionLocal(dm, time, funcs, ctxs, INSERT_BC_VALUES, localX);CHKERRQ(ierr); 1322 ierr = DMGetBasisTransformDM_Internal(dm, &tdm);CHKERRQ(ierr); 1323 ierr = DMGetBasisTransformVec_Internal(dm, &tv);CHKERRQ(ierr); 1324 ierr = DMHasBasisTransform(dm, &transform);CHKERRQ(ierr); 1325 for (field = 0; field < numFields; ++field) { 1326 PetscObject obj; 1327 PetscClassId id; 1328 PetscInt Nc; 1329 1330 ierr = DMGetField(dm, field, NULL, &obj);CHKERRQ(ierr); 1331 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 1332 if (id == PETSCFE_CLASSID) { 1333 PetscFE fe = (PetscFE) obj; 1334 1335 ierr = PetscFEGetQuadrature(fe, &quad);CHKERRQ(ierr); 1336 ierr = PetscFEGetNumComponents(fe, &Nc);CHKERRQ(ierr); 1337 } else if (id == PETSCFV_CLASSID) { 1338 PetscFV fv = (PetscFV) obj; 1339 1340 ierr = PetscFVGetQuadrature(fv, &quad);CHKERRQ(ierr); 1341 ierr = PetscFVGetNumComponents(fv, &Nc);CHKERRQ(ierr); 1342 } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", field); 1343 numComponents += Nc; 1344 } 1345 ierr = PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights);CHKERRQ(ierr); 1346 if ((qNc != 1) && (qNc != numComponents)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_SIZ, "Quadrature components %D != %D field components", qNc, numComponents); 1347 ierr = PetscCalloc7(numFields,&localDiff,numComponents,&funcVal,numComponents,&interpolant,coordDim*(Nq+1),&coords,Nq,&fegeom.detJ,coordDim*coordDim*Nq,&fegeom.J,coordDim*coordDim*Nq,&fegeom.invJ);CHKERRQ(ierr); 1348 ierr = DMPlexGetInteriorCellStratum(dm, &cStart, &cEnd);CHKERRQ(ierr); 1349 for (c = cStart; c < cEnd; ++c) { 1350 PetscScalar *x = NULL; 1351 PetscInt qc = 0; 1352 1353 ierr = DMPlexComputeCellGeometryFEM(dm, c, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ);CHKERRQ(ierr); 1354 ierr = DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr); 1355 1356 for (field = 0, fieldOffset = 0; field < numFields; ++field) { 1357 PetscObject obj; 1358 PetscClassId id; 1359 void * const ctx = ctxs ? ctxs[field] : NULL; 1360 PetscInt Nb, Nc, q, fc; 1361 1362 PetscReal elemDiff = 0.0; 1363 1364 ierr = DMGetField(dm, field, NULL, &obj);CHKERRQ(ierr); 1365 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 1366 if (id == PETSCFE_CLASSID) {ierr = PetscFEGetNumComponents((PetscFE) obj, &Nc);CHKERRQ(ierr);ierr = PetscFEGetDimension((PetscFE) obj, &Nb);CHKERRQ(ierr);} 1367 else if (id == PETSCFV_CLASSID) {ierr = PetscFVGetNumComponents((PetscFV) obj, &Nc);CHKERRQ(ierr);Nb = 1;} 1368 else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", field); 1369 if (debug) { 1370 char title[1024]; 1371 ierr = PetscSNPrintf(title, 1023, "Solution for Field %D", field);CHKERRQ(ierr); 1372 ierr = DMPrintCellVector(c, title, Nb, &x[fieldOffset]);CHKERRQ(ierr); 1373 } 1374 for (q = 0; q < Nq; ++q) { 1375 PetscFEGeom qgeom; 1376 1377 qgeom.dimEmbed = fegeom.dimEmbed; 1378 qgeom.J = &fegeom.J[q*coordDim*coordDim]; 1379 qgeom.invJ = &fegeom.invJ[q*coordDim*coordDim]; 1380 qgeom.detJ = &fegeom.detJ[q]; 1381 if (fegeom.detJ[q] <= 0.0) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %D, quadrature point %D", (double)fegeom.detJ[q], c, q); 1382 if (transform) { 1383 gcoords = &coords[coordDim*Nq]; 1384 ierr = DMPlexBasisTransformApplyReal_Internal(dm, &coords[coordDim*q], PETSC_TRUE, coordDim, &coords[coordDim*q], gcoords, dm->transformCtx);CHKERRQ(ierr); 1385 } else { 1386 gcoords = &coords[coordDim*q]; 1387 } 1388 ierr = (*funcs[field])(coordDim, time, gcoords, Nc, funcVal, ctx); 1389 if (ierr) { 1390 PetscErrorCode ierr2; 1391 ierr2 = DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr2); 1392 ierr2 = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr2); 1393 ierr2 = PetscFree7(localDiff,funcVal,interpolant,coords,fegeom.detJ,fegeom.J,fegeom.invJ);CHKERRQ(ierr2); 1394 CHKERRQ(ierr); 1395 } 1396 if (transform) {ierr = DMPlexBasisTransformApply_Internal(dm, &coords[coordDim*q], PETSC_FALSE, Nc, funcVal, funcVal, dm->transformCtx);CHKERRQ(ierr);} 1397 if (id == PETSCFE_CLASSID) {ierr = PetscFEInterpolate_Static((PetscFE) obj, &x[fieldOffset], &qgeom, q, interpolant);CHKERRQ(ierr);} 1398 else if (id == PETSCFV_CLASSID) {ierr = PetscFVInterpolate_Static((PetscFV) obj, &x[fieldOffset], q, interpolant);CHKERRQ(ierr);} 1399 else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", field); 1400 for (fc = 0; fc < Nc; ++fc) { 1401 const PetscReal wt = quadWeights[q*qNc+(qNc == 1 ? 0 : qc+fc)]; 1402 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);} 1403 elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc]))*wt*fegeom.detJ[q]; 1404 } 1405 } 1406 fieldOffset += Nb; 1407 qc += Nc; 1408 localDiff[field] += elemDiff; 1409 if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, " elem %D field %D cum diff %g\n", c, field, (double)localDiff[field]);CHKERRQ(ierr);} 1410 } 1411 ierr = DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr); 1412 } 1413 ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr); 1414 ierr = MPIU_Allreduce(localDiff, diff, numFields, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr); 1415 for (field = 0; field < numFields; ++field) diff[field] = PetscSqrtReal(diff[field]); 1416 ierr = PetscFree7(localDiff,funcVal,interpolant,coords,fegeom.detJ,fegeom.J,fegeom.invJ);CHKERRQ(ierr); 1417 PetscFunctionReturn(0); 1418 } 1419 1420 /*@C 1421 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. 1422 1423 Collective on dm 1424 1425 Input Parameters: 1426 + dm - The DM 1427 . time - The time 1428 . funcs - The functions to evaluate for each field component: NULL means that component does not contribute to error calculation 1429 . ctxs - Optional array of contexts to pass to each function, or NULL. 1430 - X - The coefficient vector u_h 1431 1432 Output Parameter: 1433 . D - A Vec which holds the difference ||u - u_h||_2 for each cell 1434 1435 Level: developer 1436 1437 .seealso: DMProjectFunction(), DMComputeL2Diff(), DMPlexComputeL2FieldDiff(), DMComputeL2GradientDiff() 1438 @*/ 1439 PetscErrorCode DMPlexComputeL2DiffVec(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, Vec D) 1440 { 1441 PetscSection section; 1442 PetscQuadrature quad; 1443 Vec localX; 1444 PetscFEGeom fegeom; 1445 PetscScalar *funcVal, *interpolant; 1446 PetscReal *coords; 1447 const PetscReal *quadPoints, *quadWeights; 1448 PetscInt dim, coordDim, numFields, numComponents = 0, qNc, Nq, cStart, cEnd, c, field, fieldOffset; 1449 PetscErrorCode ierr; 1450 1451 PetscFunctionBegin; 1452 ierr = VecSet(D, 0.0);CHKERRQ(ierr); 1453 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 1454 ierr = DMGetCoordinateDim(dm, &coordDim);CHKERRQ(ierr); 1455 ierr = DMGetLocalSection(dm, §ion);CHKERRQ(ierr); 1456 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 1457 ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr); 1458 ierr = DMProjectFunctionLocal(dm, time, funcs, ctxs, INSERT_BC_VALUES, localX);CHKERRQ(ierr); 1459 ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr); 1460 ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr); 1461 for (field = 0; field < numFields; ++field) { 1462 PetscObject obj; 1463 PetscClassId id; 1464 PetscInt Nc; 1465 1466 ierr = DMGetField(dm, field, NULL, &obj);CHKERRQ(ierr); 1467 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 1468 if (id == PETSCFE_CLASSID) { 1469 PetscFE fe = (PetscFE) obj; 1470 1471 ierr = PetscFEGetQuadrature(fe, &quad);CHKERRQ(ierr); 1472 ierr = PetscFEGetNumComponents(fe, &Nc);CHKERRQ(ierr); 1473 } else if (id == PETSCFV_CLASSID) { 1474 PetscFV fv = (PetscFV) obj; 1475 1476 ierr = PetscFVGetQuadrature(fv, &quad);CHKERRQ(ierr); 1477 ierr = PetscFVGetNumComponents(fv, &Nc);CHKERRQ(ierr); 1478 } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", field); 1479 numComponents += Nc; 1480 } 1481 ierr = PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights);CHKERRQ(ierr); 1482 if ((qNc != 1) && (qNc != numComponents)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_SIZ, "Quadrature components %D != %D field components", qNc, numComponents); 1483 ierr = PetscMalloc6(numComponents,&funcVal,numComponents,&interpolant,coordDim*Nq,&coords,Nq,&fegeom.detJ,coordDim*coordDim*Nq,&fegeom.J,coordDim*coordDim*Nq,&fegeom.invJ);CHKERRQ(ierr); 1484 ierr = DMPlexGetInteriorCellStratum(dm, &cStart, &cEnd);CHKERRQ(ierr); 1485 for (c = cStart; c < cEnd; ++c) { 1486 PetscScalar *x = NULL; 1487 PetscScalar elemDiff = 0.0; 1488 PetscInt qc = 0; 1489 1490 ierr = DMPlexComputeCellGeometryFEM(dm, c, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ);CHKERRQ(ierr); 1491 ierr = DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr); 1492 1493 for (field = 0, fieldOffset = 0; field < numFields; ++field) { 1494 PetscObject obj; 1495 PetscClassId id; 1496 void * const ctx = ctxs ? ctxs[field] : NULL; 1497 PetscInt Nb, Nc, q, fc; 1498 1499 ierr = DMGetField(dm, field, NULL, &obj);CHKERRQ(ierr); 1500 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 1501 if (id == PETSCFE_CLASSID) {ierr = PetscFEGetNumComponents((PetscFE) obj, &Nc);CHKERRQ(ierr);ierr = PetscFEGetDimension((PetscFE) obj, &Nb);CHKERRQ(ierr);} 1502 else if (id == PETSCFV_CLASSID) {ierr = PetscFVGetNumComponents((PetscFV) obj, &Nc);CHKERRQ(ierr);Nb = 1;} 1503 else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", field); 1504 if (funcs[field]) { 1505 for (q = 0; q < Nq; ++q) { 1506 PetscFEGeom qgeom; 1507 1508 qgeom.dimEmbed = fegeom.dimEmbed; 1509 qgeom.J = &fegeom.J[q*coordDim*coordDim]; 1510 qgeom.invJ = &fegeom.invJ[q*coordDim*coordDim]; 1511 qgeom.detJ = &fegeom.detJ[q]; 1512 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); 1513 ierr = (*funcs[field])(coordDim, time, &coords[q*coordDim], Nc, funcVal, ctx); 1514 if (ierr) { 1515 PetscErrorCode ierr2; 1516 ierr2 = DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr2); 1517 ierr2 = PetscFree6(funcVal,interpolant,coords,fegeom.detJ,fegeom.J,fegeom.invJ);CHKERRQ(ierr2); 1518 ierr2 = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr2); 1519 CHKERRQ(ierr); 1520 } 1521 if (id == PETSCFE_CLASSID) {ierr = PetscFEInterpolate_Static((PetscFE) obj, &x[fieldOffset], &qgeom, q, interpolant);CHKERRQ(ierr);} 1522 else if (id == PETSCFV_CLASSID) {ierr = PetscFVInterpolate_Static((PetscFV) obj, &x[fieldOffset], q, interpolant);CHKERRQ(ierr);} 1523 else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", field); 1524 for (fc = 0; fc < Nc; ++fc) { 1525 const PetscReal wt = quadWeights[q*qNc+(qNc == 1 ? 0 : qc+fc)]; 1526 elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc]))*wt*fegeom.detJ[q]; 1527 } 1528 } 1529 } 1530 fieldOffset += Nb; 1531 qc += Nc; 1532 } 1533 ierr = DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr); 1534 ierr = VecSetValue(D, c - cStart, elemDiff, INSERT_VALUES);CHKERRQ(ierr); 1535 } 1536 ierr = PetscFree6(funcVal,interpolant,coords,fegeom.detJ,fegeom.J,fegeom.invJ);CHKERRQ(ierr); 1537 ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr); 1538 ierr = VecSqrtAbs(D);CHKERRQ(ierr); 1539 PetscFunctionReturn(0); 1540 } 1541 1542 /*@C 1543 DMPlexComputeGradientClementInterpolant - This function computes the L2 projection of the cellwise gradient of a function u onto P1, and stores it in a Vec. 1544 1545 Collective on dm 1546 1547 Input Parameters: 1548 + dm - The DM 1549 - LocX - The coefficient vector u_h 1550 1551 Output Parameter: 1552 . locC - A Vec which holds the Clement interpolant of the gradient 1553 1554 Notes: 1555 Add citation to (Clement, 1975) and definition of the interpolant 1556 \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 1557 1558 Level: developer 1559 1560 .seealso: DMProjectFunction(), DMComputeL2Diff(), DMPlexComputeL2FieldDiff(), DMComputeL2GradientDiff() 1561 @*/ 1562 PetscErrorCode DMPlexComputeGradientClementInterpolant(DM dm, Vec locX, Vec locC) 1563 { 1564 DM_Plex *mesh = (DM_Plex *) dm->data; 1565 PetscInt debug = mesh->printFEM; 1566 DM dmC; 1567 PetscSection section; 1568 PetscQuadrature quad; 1569 PetscScalar *interpolant, *gradsum; 1570 PetscFEGeom fegeom; 1571 PetscReal *coords; 1572 const PetscReal *quadPoints, *quadWeights; 1573 PetscInt dim, coordDim, numFields, numComponents = 0, qNc, Nq, cStart, cEnd, vStart, vEnd, v, field, fieldOffset; 1574 PetscErrorCode ierr; 1575 1576 PetscFunctionBegin; 1577 ierr = VecGetDM(locC, &dmC);CHKERRQ(ierr); 1578 ierr = VecSet(locC, 0.0);CHKERRQ(ierr); 1579 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 1580 ierr = DMGetCoordinateDim(dm, &coordDim);CHKERRQ(ierr); 1581 fegeom.dimEmbed = coordDim; 1582 ierr = DMGetLocalSection(dm, §ion);CHKERRQ(ierr); 1583 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 1584 for (field = 0; field < numFields; ++field) { 1585 PetscObject obj; 1586 PetscClassId id; 1587 PetscInt Nc; 1588 1589 ierr = DMGetField(dm, field, NULL, &obj);CHKERRQ(ierr); 1590 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 1591 if (id == PETSCFE_CLASSID) { 1592 PetscFE fe = (PetscFE) obj; 1593 1594 ierr = PetscFEGetQuadrature(fe, &quad);CHKERRQ(ierr); 1595 ierr = PetscFEGetNumComponents(fe, &Nc);CHKERRQ(ierr); 1596 } else if (id == PETSCFV_CLASSID) { 1597 PetscFV fv = (PetscFV) obj; 1598 1599 ierr = PetscFVGetQuadrature(fv, &quad);CHKERRQ(ierr); 1600 ierr = PetscFVGetNumComponents(fv, &Nc);CHKERRQ(ierr); 1601 } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", field); 1602 numComponents += Nc; 1603 } 1604 ierr = PetscQuadratureGetData(quad, NULL, &qNc, &Nq, &quadPoints, &quadWeights);CHKERRQ(ierr); 1605 if ((qNc != 1) && (qNc != numComponents)) SETERRQ2(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_SIZ, "Quadrature components %D != %D field components", qNc, numComponents); 1606 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); 1607 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 1608 ierr = DMPlexGetInteriorCellStratum(dm, &cStart, &cEnd);CHKERRQ(ierr); 1609 for (v = vStart; v < vEnd; ++v) { 1610 PetscScalar volsum = 0.0; 1611 PetscInt *star = NULL; 1612 PetscInt starSize, st, d, fc; 1613 1614 ierr = PetscArrayzero(gradsum, coordDim*numComponents);CHKERRQ(ierr); 1615 ierr = DMPlexGetTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr); 1616 for (st = 0; st < starSize*2; st += 2) { 1617 const PetscInt cell = star[st]; 1618 PetscScalar *grad = &gradsum[coordDim*numComponents]; 1619 PetscScalar *x = NULL; 1620 PetscReal vol = 0.0; 1621 1622 if ((cell < cStart) || (cell >= cEnd)) continue; 1623 ierr = DMPlexComputeCellGeometryFEM(dm, cell, quad, coords, fegeom.J, fegeom.invJ, fegeom.detJ);CHKERRQ(ierr); 1624 ierr = DMPlexVecGetClosure(dm, NULL, locX, cell, NULL, &x);CHKERRQ(ierr); 1625 for (field = 0, fieldOffset = 0; field < numFields; ++field) { 1626 PetscObject obj; 1627 PetscClassId id; 1628 PetscInt Nb, Nc, q, qc = 0; 1629 1630 ierr = PetscArrayzero(grad, coordDim*numComponents);CHKERRQ(ierr); 1631 ierr = DMGetField(dm, field, NULL, &obj);CHKERRQ(ierr); 1632 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 1633 if (id == PETSCFE_CLASSID) {ierr = PetscFEGetNumComponents((PetscFE) obj, &Nc);CHKERRQ(ierr);ierr = PetscFEGetDimension((PetscFE) obj, &Nb);CHKERRQ(ierr);} 1634 else if (id == PETSCFV_CLASSID) {ierr = PetscFVGetNumComponents((PetscFV) obj, &Nc);CHKERRQ(ierr);Nb = 1;} 1635 else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", field); 1636 for (q = 0; q < Nq; ++q) { 1637 PetscFEGeom qgeom; 1638 1639 qgeom.dimEmbed = fegeom.dimEmbed; 1640 qgeom.J = &fegeom.J[q*coordDim*coordDim]; 1641 qgeom.invJ = &fegeom.invJ[q*coordDim*coordDim]; 1642 qgeom.detJ = &fegeom.detJ[q]; 1643 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); 1644 if (ierr) { 1645 PetscErrorCode ierr2; 1646 ierr2 = DMPlexVecRestoreClosure(dm, NULL, locX, cell, NULL, &x);CHKERRQ(ierr2); 1647 ierr2 = DMPlexRestoreTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr2); 1648 ierr2 = PetscFree6(gradsum,interpolant,coords,fegeom.detJ,fegeom.J,fegeom.invJ);CHKERRQ(ierr2); 1649 CHKERRQ(ierr); 1650 } 1651 if (id == PETSCFE_CLASSID) {ierr = PetscFEInterpolateGradient_Static((PetscFE) obj, &x[fieldOffset], &qgeom, q, interpolant);CHKERRQ(ierr);} 1652 else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", field); 1653 for (fc = 0; fc < Nc; ++fc) { 1654 const PetscReal wt = quadWeights[q*qNc+qc+fc]; 1655 1656 for (d = 0; d < coordDim; ++d) grad[fc*coordDim+d] += interpolant[fc*dim+d]*wt*fegeom.detJ[q]; 1657 } 1658 vol += quadWeights[q*qNc]*fegeom.detJ[q]; 1659 } 1660 fieldOffset += Nb; 1661 qc += Nc; 1662 } 1663 ierr = DMPlexVecRestoreClosure(dm, NULL, locX, cell, NULL, &x);CHKERRQ(ierr); 1664 for (fc = 0; fc < numComponents; ++fc) { 1665 for (d = 0; d < coordDim; ++d) { 1666 gradsum[fc*coordDim+d] += grad[fc*coordDim+d]; 1667 } 1668 } 1669 volsum += vol; 1670 if (debug) { 1671 ierr = PetscPrintf(PETSC_COMM_SELF, "Cell %D gradient: [", cell);CHKERRQ(ierr); 1672 for (fc = 0; fc < numComponents; ++fc) { 1673 for (d = 0; d < coordDim; ++d) { 1674 if (fc || d > 0) {ierr = PetscPrintf(PETSC_COMM_SELF, ", ");CHKERRQ(ierr);} 1675 ierr = PetscPrintf(PETSC_COMM_SELF, "%g", (double)PetscRealPart(grad[fc*coordDim+d]));CHKERRQ(ierr); 1676 } 1677 } 1678 ierr = PetscPrintf(PETSC_COMM_SELF, "]\n");CHKERRQ(ierr); 1679 } 1680 } 1681 for (fc = 0; fc < numComponents; ++fc) { 1682 for (d = 0; d < coordDim; ++d) gradsum[fc*coordDim+d] /= volsum; 1683 } 1684 ierr = DMPlexRestoreTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr); 1685 ierr = DMPlexVecSetClosure(dmC, NULL, locC, v, gradsum, INSERT_VALUES);CHKERRQ(ierr); 1686 } 1687 ierr = PetscFree6(gradsum,interpolant,coords,fegeom.detJ,fegeom.J,fegeom.invJ);CHKERRQ(ierr); 1688 PetscFunctionReturn(0); 1689 } 1690 1691 static PetscErrorCode DMPlexComputeIntegral_Internal(DM dm, Vec X, PetscInt cStart, PetscInt cEnd, PetscScalar *cintegral, void *user) 1692 { 1693 DM dmAux = NULL; 1694 PetscDS prob, probAux = NULL; 1695 PetscSection section, sectionAux; 1696 Vec locX, locA; 1697 PetscInt dim, numCells = cEnd - cStart, c, f; 1698 PetscBool useFVM = PETSC_FALSE; 1699 /* DS */ 1700 PetscInt Nf, totDim, *uOff, *uOff_x, numConstants; 1701 PetscInt NfAux, totDimAux, *aOff; 1702 PetscScalar *u, *a; 1703 const PetscScalar *constants; 1704 /* Geometry */ 1705 PetscFEGeom *cgeomFEM; 1706 DM dmGrad; 1707 PetscQuadrature affineQuad = NULL; 1708 Vec cellGeometryFVM = NULL, faceGeometryFVM = NULL, locGrad = NULL; 1709 PetscFVCellGeom *cgeomFVM; 1710 const PetscScalar *lgrad; 1711 PetscInt maxDegree; 1712 DMField coordField; 1713 IS cellIS; 1714 PetscErrorCode ierr; 1715 1716 PetscFunctionBegin; 1717 ierr = DMGetDS(dm, &prob);CHKERRQ(ierr); 1718 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 1719 ierr = DMGetLocalSection(dm, §ion);CHKERRQ(ierr); 1720 ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr); 1721 /* Determine which discretizations we have */ 1722 for (f = 0; f < Nf; ++f) { 1723 PetscObject obj; 1724 PetscClassId id; 1725 1726 ierr = PetscDSGetDiscretization(prob, f, &obj);CHKERRQ(ierr); 1727 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 1728 if (id == PETSCFV_CLASSID) useFVM = PETSC_TRUE; 1729 } 1730 /* Get local solution with boundary values */ 1731 ierr = DMGetLocalVector(dm, &locX);CHKERRQ(ierr); 1732 ierr = DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locX, 0.0, NULL, NULL, NULL);CHKERRQ(ierr); 1733 ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, locX);CHKERRQ(ierr); 1734 ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, locX);CHKERRQ(ierr); 1735 /* Read DS information */ 1736 ierr = PetscDSGetTotalDimension(prob, &totDim);CHKERRQ(ierr); 1737 ierr = PetscDSGetComponentOffsets(prob, &uOff);CHKERRQ(ierr); 1738 ierr = PetscDSGetComponentDerivativeOffsets(prob, &uOff_x);CHKERRQ(ierr); 1739 ierr = ISCreateStride(PETSC_COMM_SELF,numCells,cStart,1,&cellIS);CHKERRQ(ierr); 1740 ierr = PetscDSGetConstants(prob, &numConstants, &constants);CHKERRQ(ierr); 1741 /* Read Auxiliary DS information */ 1742 ierr = PetscObjectQuery((PetscObject) dm, "dmAux", (PetscObject *) &dmAux);CHKERRQ(ierr); 1743 ierr = PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &locA);CHKERRQ(ierr); 1744 if (dmAux) { 1745 ierr = DMGetDS(dmAux, &probAux);CHKERRQ(ierr); 1746 ierr = PetscDSGetNumFields(probAux, &NfAux);CHKERRQ(ierr); 1747 ierr = DMGetLocalSection(dmAux, §ionAux);CHKERRQ(ierr); 1748 ierr = PetscDSGetTotalDimension(probAux, &totDimAux);CHKERRQ(ierr); 1749 ierr = PetscDSGetComponentOffsets(probAux, &aOff);CHKERRQ(ierr); 1750 } 1751 /* Allocate data arrays */ 1752 ierr = PetscCalloc1(numCells*totDim, &u);CHKERRQ(ierr); 1753 if (dmAux) {ierr = PetscMalloc1(numCells*totDimAux, &a);CHKERRQ(ierr);} 1754 /* Read out geometry */ 1755 ierr = DMGetCoordinateField(dm,&coordField);CHKERRQ(ierr); 1756 ierr = DMFieldGetDegree(coordField,cellIS,NULL,&maxDegree);CHKERRQ(ierr); 1757 if (maxDegree <= 1) { 1758 ierr = DMFieldCreateDefaultQuadrature(coordField,cellIS,&affineQuad);CHKERRQ(ierr); 1759 if (affineQuad) { 1760 ierr = DMFieldCreateFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&cgeomFEM);CHKERRQ(ierr); 1761 } 1762 } 1763 if (useFVM) { 1764 PetscFV fv = NULL; 1765 Vec grad; 1766 PetscInt fStart, fEnd; 1767 PetscBool compGrad; 1768 1769 for (f = 0; f < Nf; ++f) { 1770 PetscObject obj; 1771 PetscClassId id; 1772 1773 ierr = PetscDSGetDiscretization(prob, f, &obj);CHKERRQ(ierr); 1774 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 1775 if (id == PETSCFV_CLASSID) {fv = (PetscFV) obj; break;} 1776 } 1777 ierr = PetscFVGetComputeGradients(fv, &compGrad);CHKERRQ(ierr); 1778 ierr = PetscFVSetComputeGradients(fv, PETSC_TRUE);CHKERRQ(ierr); 1779 ierr = DMPlexComputeGeometryFVM(dm, &cellGeometryFVM, &faceGeometryFVM);CHKERRQ(ierr); 1780 ierr = DMPlexComputeGradientFVM(dm, fv, faceGeometryFVM, cellGeometryFVM, &dmGrad);CHKERRQ(ierr); 1781 ierr = PetscFVSetComputeGradients(fv, compGrad);CHKERRQ(ierr); 1782 ierr = VecGetArrayRead(cellGeometryFVM, (const PetscScalar **) &cgeomFVM);CHKERRQ(ierr); 1783 /* Reconstruct and limit cell gradients */ 1784 ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr); 1785 ierr = DMGetGlobalVector(dmGrad, &grad);CHKERRQ(ierr); 1786 ierr = DMPlexReconstructGradients_Internal(dm, fv, fStart, fEnd, faceGeometryFVM, cellGeometryFVM, locX, grad);CHKERRQ(ierr); 1787 /* Communicate gradient values */ 1788 ierr = DMGetLocalVector(dmGrad, &locGrad);CHKERRQ(ierr); 1789 ierr = DMGlobalToLocalBegin(dmGrad, grad, INSERT_VALUES, locGrad);CHKERRQ(ierr); 1790 ierr = DMGlobalToLocalEnd(dmGrad, grad, INSERT_VALUES, locGrad);CHKERRQ(ierr); 1791 ierr = DMRestoreGlobalVector(dmGrad, &grad);CHKERRQ(ierr); 1792 /* Handle non-essential (e.g. outflow) boundary values */ 1793 ierr = DMPlexInsertBoundaryValues(dm, PETSC_FALSE, locX, 0.0, faceGeometryFVM, cellGeometryFVM, locGrad);CHKERRQ(ierr); 1794 ierr = VecGetArrayRead(locGrad, &lgrad);CHKERRQ(ierr); 1795 } 1796 /* Read out data from inputs */ 1797 for (c = cStart; c < cEnd; ++c) { 1798 PetscScalar *x = NULL; 1799 PetscInt i; 1800 1801 ierr = DMPlexVecGetClosure(dm, section, locX, c, NULL, &x);CHKERRQ(ierr); 1802 for (i = 0; i < totDim; ++i) u[c*totDim+i] = x[i]; 1803 ierr = DMPlexVecRestoreClosure(dm, section, locX, c, NULL, &x);CHKERRQ(ierr); 1804 if (dmAux) { 1805 ierr = DMPlexVecGetClosure(dmAux, sectionAux, locA, c, NULL, &x);CHKERRQ(ierr); 1806 for (i = 0; i < totDimAux; ++i) a[c*totDimAux+i] = x[i]; 1807 ierr = DMPlexVecRestoreClosure(dmAux, sectionAux, locA, c, NULL, &x);CHKERRQ(ierr); 1808 } 1809 } 1810 /* Do integration for each field */ 1811 for (f = 0; f < Nf; ++f) { 1812 PetscObject obj; 1813 PetscClassId id; 1814 PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset; 1815 1816 ierr = PetscDSGetDiscretization(prob, f, &obj);CHKERRQ(ierr); 1817 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 1818 if (id == PETSCFE_CLASSID) { 1819 PetscFE fe = (PetscFE) obj; 1820 PetscQuadrature q; 1821 PetscFEGeom *chunkGeom = NULL; 1822 PetscInt Nq, Nb; 1823 1824 ierr = PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);CHKERRQ(ierr); 1825 ierr = PetscFEGetQuadrature(fe, &q);CHKERRQ(ierr); 1826 ierr = PetscQuadratureGetData(q, NULL, NULL, &Nq, NULL, NULL);CHKERRQ(ierr); 1827 ierr = PetscFEGetDimension(fe, &Nb);CHKERRQ(ierr); 1828 blockSize = Nb*Nq; 1829 batchSize = numBlocks * blockSize; 1830 ierr = PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);CHKERRQ(ierr); 1831 numChunks = numCells / (numBatches*batchSize); 1832 Ne = numChunks*numBatches*batchSize; 1833 Nr = numCells % (numBatches*batchSize); 1834 offset = numCells - Nr; 1835 if (!affineQuad) { 1836 ierr = DMFieldCreateFEGeom(coordField,cellIS,q,PETSC_FALSE,&cgeomFEM);CHKERRQ(ierr); 1837 } 1838 ierr = PetscFEGeomGetChunk(cgeomFEM,0,offset,&chunkGeom);CHKERRQ(ierr); 1839 ierr = PetscFEIntegrate(prob, f, Ne, chunkGeom, u, probAux, a, cintegral);CHKERRQ(ierr); 1840 ierr = PetscFEGeomGetChunk(cgeomFEM,offset,numCells,&chunkGeom);CHKERRQ(ierr); 1841 ierr = PetscFEIntegrate(prob, f, Nr, chunkGeom, &u[offset*totDim], probAux, &a[offset*totDimAux], &cintegral[offset*Nf]);CHKERRQ(ierr); 1842 ierr = PetscFEGeomRestoreChunk(cgeomFEM,offset,numCells,&chunkGeom);CHKERRQ(ierr); 1843 if (!affineQuad) { 1844 ierr = PetscFEGeomDestroy(&cgeomFEM);CHKERRQ(ierr); 1845 } 1846 } else if (id == PETSCFV_CLASSID) { 1847 PetscInt foff; 1848 PetscPointFunc obj_func; 1849 PetscScalar lint; 1850 1851 ierr = PetscDSGetObjective(prob, f, &obj_func);CHKERRQ(ierr); 1852 ierr = PetscDSGetFieldOffset(prob, f, &foff);CHKERRQ(ierr); 1853 if (obj_func) { 1854 for (c = 0; c < numCells; ++c) { 1855 PetscScalar *u_x; 1856 1857 ierr = DMPlexPointLocalRead(dmGrad, c, lgrad, &u_x);CHKERRQ(ierr); 1858 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); 1859 cintegral[c*Nf+f] += PetscRealPart(lint)*cgeomFVM[c].volume; 1860 } 1861 } 1862 } else SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", f); 1863 } 1864 /* Cleanup data arrays */ 1865 if (useFVM) { 1866 ierr = VecRestoreArrayRead(locGrad, &lgrad);CHKERRQ(ierr); 1867 ierr = VecRestoreArrayRead(cellGeometryFVM, (const PetscScalar **) &cgeomFVM);CHKERRQ(ierr); 1868 ierr = DMRestoreLocalVector(dmGrad, &locGrad);CHKERRQ(ierr); 1869 ierr = VecDestroy(&faceGeometryFVM);CHKERRQ(ierr); 1870 ierr = VecDestroy(&cellGeometryFVM);CHKERRQ(ierr); 1871 ierr = DMDestroy(&dmGrad);CHKERRQ(ierr); 1872 } 1873 if (dmAux) {ierr = PetscFree(a);CHKERRQ(ierr);} 1874 ierr = PetscFree(u);CHKERRQ(ierr); 1875 /* Cleanup */ 1876 if (affineQuad) { 1877 ierr = PetscFEGeomDestroy(&cgeomFEM);CHKERRQ(ierr); 1878 } 1879 ierr = PetscQuadratureDestroy(&affineQuad);CHKERRQ(ierr); 1880 ierr = ISDestroy(&cellIS);CHKERRQ(ierr); 1881 ierr = DMRestoreLocalVector(dm, &locX);CHKERRQ(ierr); 1882 PetscFunctionReturn(0); 1883 } 1884 1885 /*@ 1886 DMPlexComputeIntegralFEM - Form the integral over the domain from the global input X using pointwise functions specified by the user 1887 1888 Input Parameters: 1889 + dm - The mesh 1890 . X - Global input vector 1891 - user - The user context 1892 1893 Output Parameter: 1894 . integral - Integral for each field 1895 1896 Level: developer 1897 1898 .seealso: DMPlexComputeResidualFEM() 1899 @*/ 1900 PetscErrorCode DMPlexComputeIntegralFEM(DM dm, Vec X, PetscScalar *integral, void *user) 1901 { 1902 DM_Plex *mesh = (DM_Plex *) dm->data; 1903 PetscScalar *cintegral, *lintegral; 1904 PetscInt Nf, f, cellHeight, cStart, cEnd, cEndInterior[4], cell; 1905 PetscErrorCode ierr; 1906 1907 PetscFunctionBegin; 1908 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1909 PetscValidHeaderSpecific(X, VEC_CLASSID, 2); 1910 PetscValidPointer(integral, 3); 1911 ierr = PetscLogEventBegin(DMPLEX_IntegralFEM,dm,0,0,0);CHKERRQ(ierr); 1912 ierr = DMGetNumFields(dm, &Nf);CHKERRQ(ierr); 1913 ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr); 1914 ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr); 1915 ierr = DMPlexGetHybridBounds(dm, &cEndInterior[0], &cEndInterior[1], &cEndInterior[2], &cEndInterior[3]);CHKERRQ(ierr); 1916 cEnd = cEndInterior[cellHeight] < 0 ? cEnd : cEndInterior[cellHeight]; 1917 /* TODO Introduce a loop over large chunks (right now this is a single chunk) */ 1918 ierr = PetscCalloc2(Nf, &lintegral, (cEnd-cStart)*Nf, &cintegral);CHKERRQ(ierr); 1919 ierr = DMPlexComputeIntegral_Internal(dm, X, cStart, cEnd, cintegral, user);CHKERRQ(ierr); 1920 /* Sum up values */ 1921 for (cell = cStart; cell < cEnd; ++cell) { 1922 const PetscInt c = cell - cStart; 1923 1924 if (mesh->printFEM > 1) {ierr = DMPrintCellVector(cell, "Cell Integral", Nf, &cintegral[c*Nf]);CHKERRQ(ierr);} 1925 for (f = 0; f < Nf; ++f) lintegral[f] += cintegral[c*Nf+f]; 1926 } 1927 ierr = MPIU_Allreduce(lintegral, integral, Nf, MPIU_SCALAR, MPIU_SUM, PetscObjectComm((PetscObject) dm));CHKERRQ(ierr); 1928 if (mesh->printFEM) { 1929 ierr = PetscPrintf(PetscObjectComm((PetscObject) dm), "Integral:");CHKERRQ(ierr); 1930 for (f = 0; f < Nf; ++f) {ierr = PetscPrintf(PetscObjectComm((PetscObject) dm), " %g", (double) PetscRealPart(integral[f]));CHKERRQ(ierr);} 1931 ierr = PetscPrintf(PetscObjectComm((PetscObject) dm), "\n");CHKERRQ(ierr); 1932 } 1933 ierr = PetscFree2(lintegral, cintegral);CHKERRQ(ierr); 1934 ierr = PetscLogEventEnd(DMPLEX_IntegralFEM,dm,0,0,0);CHKERRQ(ierr); 1935 PetscFunctionReturn(0); 1936 } 1937 1938 /*@ 1939 DMPlexComputeCellwiseIntegralFEM - Form the vector of cellwise integrals F from the global input X using pointwise functions specified by the user 1940 1941 Input Parameters: 1942 + dm - The mesh 1943 . X - Global input vector 1944 - user - The user context 1945 1946 Output Parameter: 1947 . integral - Cellwise integrals for each field 1948 1949 Level: developer 1950 1951 .seealso: DMPlexComputeResidualFEM() 1952 @*/ 1953 PetscErrorCode DMPlexComputeCellwiseIntegralFEM(DM dm, Vec X, Vec F, void *user) 1954 { 1955 DM_Plex *mesh = (DM_Plex *) dm->data; 1956 DM dmF; 1957 PetscSection sectionF; 1958 PetscScalar *cintegral, *af; 1959 PetscInt Nf, f, cellHeight, cStart, cEnd, cEndInterior[4], cell; 1960 PetscErrorCode ierr; 1961 1962 PetscFunctionBegin; 1963 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1964 PetscValidHeaderSpecific(X, VEC_CLASSID, 2); 1965 PetscValidHeaderSpecific(F, VEC_CLASSID, 3); 1966 ierr = PetscLogEventBegin(DMPLEX_IntegralFEM,dm,0,0,0);CHKERRQ(ierr); 1967 ierr = DMGetNumFields(dm, &Nf);CHKERRQ(ierr); 1968 ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr); 1969 ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr); 1970 ierr = DMPlexGetHybridBounds(dm, &cEndInterior[0], &cEndInterior[1], &cEndInterior[2], &cEndInterior[3]);CHKERRQ(ierr); 1971 cEnd = cEndInterior[cellHeight] < 0 ? cEnd : cEndInterior[cellHeight]; 1972 /* TODO Introduce a loop over large chunks (right now this is a single chunk) */ 1973 ierr = PetscCalloc1((cEnd-cStart)*Nf, &cintegral);CHKERRQ(ierr); 1974 ierr = DMPlexComputeIntegral_Internal(dm, X, cStart, cEnd, cintegral, user);CHKERRQ(ierr); 1975 /* Put values in F*/ 1976 ierr = VecGetDM(F, &dmF);CHKERRQ(ierr); 1977 ierr = DMGetLocalSection(dmF, §ionF);CHKERRQ(ierr); 1978 ierr = VecGetArray(F, &af);CHKERRQ(ierr); 1979 for (cell = cStart; cell < cEnd; ++cell) { 1980 const PetscInt c = cell - cStart; 1981 PetscInt dof, off; 1982 1983 if (mesh->printFEM > 1) {ierr = DMPrintCellVector(cell, "Cell Integral", Nf, &cintegral[c*Nf]);CHKERRQ(ierr);} 1984 ierr = PetscSectionGetDof(sectionF, cell, &dof);CHKERRQ(ierr); 1985 ierr = PetscSectionGetOffset(sectionF, cell, &off);CHKERRQ(ierr); 1986 if (dof != Nf) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "The number of cell dofs %D != %D", dof, Nf); 1987 for (f = 0; f < Nf; ++f) af[off+f] = cintegral[c*Nf+f]; 1988 } 1989 ierr = VecRestoreArray(F, &af);CHKERRQ(ierr); 1990 ierr = PetscFree(cintegral);CHKERRQ(ierr); 1991 ierr = PetscLogEventEnd(DMPLEX_IntegralFEM,dm,0,0,0);CHKERRQ(ierr); 1992 PetscFunctionReturn(0); 1993 } 1994 1995 static PetscErrorCode DMPlexComputeBdIntegral_Internal(DM dm, Vec locX, IS pointIS, 1996 void (*func)(PetscInt, PetscInt, PetscInt, 1997 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 1998 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 1999 PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), 2000 PetscScalar *fintegral, void *user) 2001 { 2002 DM plex = NULL, plexA = NULL; 2003 PetscDS prob, probAux = NULL; 2004 PetscSection section, sectionAux = NULL; 2005 Vec locA = NULL; 2006 DMField coordField; 2007 PetscInt Nf, totDim, *uOff, *uOff_x; 2008 PetscInt NfAux = 0, totDimAux = 0, *aOff = NULL; 2009 PetscScalar *u, *a = NULL; 2010 const PetscScalar *constants; 2011 PetscInt numConstants, f; 2012 PetscErrorCode ierr; 2013 2014 PetscFunctionBegin; 2015 ierr = DMGetCoordinateField(dm, &coordField);CHKERRQ(ierr); 2016 ierr = DMConvert(dm, DMPLEX, &plex);CHKERRQ(ierr); 2017 ierr = DMGetDS(dm, &prob);CHKERRQ(ierr); 2018 ierr = DMGetLocalSection(dm, §ion);CHKERRQ(ierr); 2019 ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr); 2020 /* Determine which discretizations we have */ 2021 for (f = 0; f < Nf; ++f) { 2022 PetscObject obj; 2023 PetscClassId id; 2024 2025 ierr = PetscDSGetDiscretization(prob, f, &obj);CHKERRQ(ierr); 2026 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 2027 if (id == PETSCFV_CLASSID) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Not supported for FVM (field %D)", f); 2028 } 2029 /* Read DS information */ 2030 ierr = PetscDSGetTotalDimension(prob, &totDim);CHKERRQ(ierr); 2031 ierr = PetscDSGetComponentOffsets(prob, &uOff);CHKERRQ(ierr); 2032 ierr = PetscDSGetComponentDerivativeOffsets(prob, &uOff_x);CHKERRQ(ierr); 2033 ierr = PetscDSGetConstants(prob, &numConstants, &constants);CHKERRQ(ierr); 2034 /* Read Auxiliary DS information */ 2035 ierr = PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &locA);CHKERRQ(ierr); 2036 if (locA) { 2037 DM dmAux; 2038 2039 ierr = VecGetDM(locA, &dmAux);CHKERRQ(ierr); 2040 ierr = DMConvert(dmAux, DMPLEX, &plexA);CHKERRQ(ierr); 2041 ierr = DMGetDS(dmAux, &probAux);CHKERRQ(ierr); 2042 ierr = PetscDSGetNumFields(probAux, &NfAux);CHKERRQ(ierr); 2043 ierr = DMGetLocalSection(dmAux, §ionAux);CHKERRQ(ierr); 2044 ierr = PetscDSGetTotalDimension(probAux, &totDimAux);CHKERRQ(ierr); 2045 ierr = PetscDSGetComponentOffsets(probAux, &aOff);CHKERRQ(ierr); 2046 } 2047 /* Integrate over points */ 2048 { 2049 PetscFEGeom *fgeom, *chunkGeom = NULL; 2050 PetscInt maxDegree; 2051 PetscQuadrature qGeom = NULL; 2052 const PetscInt *points; 2053 PetscInt numFaces, face, Nq, field; 2054 PetscInt numChunks, chunkSize, chunk, Nr, offset; 2055 2056 ierr = ISGetLocalSize(pointIS, &numFaces);CHKERRQ(ierr); 2057 ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr); 2058 ierr = PetscCalloc2(numFaces*totDim, &u, locA ? numFaces*totDimAux : 0, &a);CHKERRQ(ierr); 2059 ierr = DMFieldGetDegree(coordField, pointIS, NULL, &maxDegree);CHKERRQ(ierr); 2060 for (field = 0; field < Nf; ++field) { 2061 PetscFE fe; 2062 2063 ierr = PetscDSGetDiscretization(prob, field, (PetscObject *) &fe);CHKERRQ(ierr); 2064 if (maxDegree <= 1) {ierr = DMFieldCreateDefaultQuadrature(coordField, pointIS, &qGeom);CHKERRQ(ierr);} 2065 if (!qGeom) { 2066 ierr = PetscFEGetFaceQuadrature(fe, &qGeom);CHKERRQ(ierr); 2067 ierr = PetscObjectReference((PetscObject) qGeom);CHKERRQ(ierr); 2068 } 2069 ierr = PetscQuadratureGetData(qGeom, NULL, NULL, &Nq, NULL, NULL);CHKERRQ(ierr); 2070 ierr = DMPlexGetFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom);CHKERRQ(ierr); 2071 for (face = 0; face < numFaces; ++face) { 2072 const PetscInt point = points[face], *support, *cone; 2073 PetscScalar *x = NULL; 2074 PetscInt i, coneSize, faceLoc; 2075 2076 ierr = DMPlexGetSupport(dm, point, &support);CHKERRQ(ierr); 2077 ierr = DMPlexGetConeSize(dm, support[0], &coneSize);CHKERRQ(ierr); 2078 ierr = DMPlexGetCone(dm, support[0], &cone);CHKERRQ(ierr); 2079 for (faceLoc = 0; faceLoc < coneSize; ++faceLoc) if (cone[faceLoc] == point) break; 2080 if (faceLoc == coneSize) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find face %D in cone of support[0] %D", face, support[0]); 2081 fgeom->face[face][0] = faceLoc; 2082 ierr = DMPlexVecGetClosure(plex, section, locX, support[0], NULL, &x);CHKERRQ(ierr); 2083 for (i = 0; i < totDim; ++i) u[face*totDim+i] = x[i]; 2084 ierr = DMPlexVecRestoreClosure(plex, section, locX, support[0], NULL, &x);CHKERRQ(ierr); 2085 if (locA) { 2086 PetscInt subp; 2087 ierr = DMPlexGetSubpoint(plexA, support[0], &subp);CHKERRQ(ierr); 2088 ierr = DMPlexVecGetClosure(plexA, sectionAux, locA, subp, NULL, &x);CHKERRQ(ierr); 2089 for (i = 0; i < totDimAux; ++i) a[f*totDimAux+i] = x[i]; 2090 ierr = DMPlexVecRestoreClosure(plexA, sectionAux, locA, subp, NULL, &x);CHKERRQ(ierr); 2091 } 2092 } 2093 /* Get blocking */ 2094 { 2095 PetscQuadrature q; 2096 PetscInt numBatches, batchSize, numBlocks, blockSize; 2097 PetscInt Nq, Nb; 2098 2099 ierr = PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);CHKERRQ(ierr); 2100 ierr = PetscFEGetQuadrature(fe, &q);CHKERRQ(ierr); 2101 ierr = PetscQuadratureGetData(q, NULL, NULL, &Nq, NULL, NULL);CHKERRQ(ierr); 2102 ierr = PetscFEGetDimension(fe, &Nb);CHKERRQ(ierr); 2103 blockSize = Nb*Nq; 2104 batchSize = numBlocks * blockSize; 2105 chunkSize = numBatches*batchSize; 2106 ierr = PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);CHKERRQ(ierr); 2107 numChunks = numFaces / chunkSize; 2108 Nr = numFaces % chunkSize; 2109 offset = numFaces - Nr; 2110 } 2111 /* Do integration for each field */ 2112 for (chunk = 0; chunk < numChunks; ++chunk) { 2113 ierr = PetscFEGeomGetChunk(fgeom, chunk*chunkSize, (chunk+1)*chunkSize, &chunkGeom);CHKERRQ(ierr); 2114 ierr = PetscFEIntegrateBd(prob, field, func, chunkSize, chunkGeom, u, probAux, a, fintegral);CHKERRQ(ierr); 2115 ierr = PetscFEGeomRestoreChunk(fgeom, 0, offset, &chunkGeom);CHKERRQ(ierr); 2116 } 2117 ierr = PetscFEGeomGetChunk(fgeom, offset, numFaces, &chunkGeom);CHKERRQ(ierr); 2118 ierr = PetscFEIntegrateBd(prob, field, func, Nr, chunkGeom, &u[offset*totDim], probAux, a ? &a[offset*totDimAux] : NULL, &fintegral[offset*Nf]);CHKERRQ(ierr); 2119 ierr = PetscFEGeomRestoreChunk(fgeom, offset, numFaces, &chunkGeom);CHKERRQ(ierr); 2120 /* Cleanup data arrays */ 2121 ierr = DMPlexRestoreFEGeom(coordField, pointIS, qGeom, PETSC_TRUE, &fgeom);CHKERRQ(ierr); 2122 ierr = PetscQuadratureDestroy(&qGeom);CHKERRQ(ierr); 2123 ierr = PetscFree2(u, a);CHKERRQ(ierr); 2124 ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr); 2125 } 2126 } 2127 if (plex) {ierr = DMDestroy(&plex);CHKERRQ(ierr);} 2128 if (plexA) {ierr = DMDestroy(&plexA);CHKERRQ(ierr);} 2129 PetscFunctionReturn(0); 2130 } 2131 2132 /*@ 2133 DMPlexComputeBdIntegral - Form the integral over the specified boundary from the global input X using pointwise functions specified by the user 2134 2135 Input Parameters: 2136 + dm - The mesh 2137 . X - Global input vector 2138 . label - The boundary DMLabel 2139 . numVals - The number of label values to use, or PETSC_DETERMINE for all values 2140 . vals - The label values to use, or PETSC_NULL for all values 2141 . func = The function to integrate along the boundary 2142 - user - The user context 2143 2144 Output Parameter: 2145 . integral - Integral for each field 2146 2147 Level: developer 2148 2149 .seealso: DMPlexComputeIntegralFEM(), DMPlexComputeBdResidualFEM() 2150 @*/ 2151 PetscErrorCode DMPlexComputeBdIntegral(DM dm, Vec X, DMLabel label, PetscInt numVals, const PetscInt vals[], 2152 void (*func)(PetscInt, PetscInt, PetscInt, 2153 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 2154 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 2155 PetscReal, const PetscReal[], const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), 2156 PetscScalar *integral, void *user) 2157 { 2158 Vec locX; 2159 PetscSection section; 2160 DMLabel depthLabel; 2161 IS facetIS; 2162 PetscInt dim, Nf, f, v; 2163 PetscErrorCode ierr; 2164 2165 PetscFunctionBegin; 2166 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 2167 PetscValidHeaderSpecific(X, VEC_CLASSID, 2); 2168 PetscValidPointer(label, 3); 2169 if (vals) PetscValidPointer(vals, 5); 2170 PetscValidPointer(integral, 6); 2171 ierr = PetscLogEventBegin(DMPLEX_IntegralFEM,dm,0,0,0);CHKERRQ(ierr); 2172 ierr = DMPlexGetDepthLabel(dm, &depthLabel);CHKERRQ(ierr); 2173 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 2174 ierr = DMLabelGetStratumIS(depthLabel, dim-1, &facetIS);CHKERRQ(ierr); 2175 ierr = DMGetLocalSection(dm, §ion);CHKERRQ(ierr); 2176 ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr); 2177 /* Get local solution with boundary values */ 2178 ierr = DMGetLocalVector(dm, &locX);CHKERRQ(ierr); 2179 ierr = DMPlexInsertBoundaryValues(dm, PETSC_TRUE, locX, 0.0, NULL, NULL, NULL);CHKERRQ(ierr); 2180 ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, locX);CHKERRQ(ierr); 2181 ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, locX);CHKERRQ(ierr); 2182 /* Loop over label values */ 2183 ierr = PetscArrayzero(integral, Nf);CHKERRQ(ierr); 2184 for (v = 0; v < numVals; ++v) { 2185 IS pointIS; 2186 PetscInt numFaces, face; 2187 PetscScalar *fintegral; 2188 2189 ierr = DMLabelGetStratumIS(label, vals[v], &pointIS);CHKERRQ(ierr); 2190 if (!pointIS) continue; /* No points with that id on this process */ 2191 { 2192 IS isectIS; 2193 2194 /* TODO: Special cases of ISIntersect where it is quick to check a priori if one is a superset of the other */ 2195 ierr = ISIntersect_Caching_Internal(facetIS, pointIS, &isectIS);CHKERRQ(ierr); 2196 ierr = ISDestroy(&pointIS);CHKERRQ(ierr); 2197 pointIS = isectIS; 2198 } 2199 ierr = ISGetLocalSize(pointIS, &numFaces);CHKERRQ(ierr); 2200 ierr = PetscCalloc1(numFaces*Nf, &fintegral);CHKERRQ(ierr); 2201 ierr = DMPlexComputeBdIntegral_Internal(dm, locX, pointIS, func, fintegral, user);CHKERRQ(ierr); 2202 /* Sum point contributions into integral */ 2203 for (f = 0; f < Nf; ++f) for (face = 0; face < numFaces; ++face) integral[f] += fintegral[face*Nf+f]; 2204 ierr = PetscFree(fintegral);CHKERRQ(ierr); 2205 ierr = ISDestroy(&pointIS);CHKERRQ(ierr); 2206 } 2207 ierr = DMRestoreLocalVector(dm, &locX);CHKERRQ(ierr); 2208 ierr = ISDestroy(&facetIS);CHKERRQ(ierr); 2209 ierr = PetscLogEventEnd(DMPLEX_IntegralFEM,dm,0,0,0);CHKERRQ(ierr); 2210 PetscFunctionReturn(0); 2211 } 2212 2213 /*@ 2214 DMPlexComputeInterpolatorNested - Form the local portion of the interpolation matrix I from the coarse DM to the uniformly refined DM. 2215 2216 Input Parameters: 2217 + dmf - The fine mesh 2218 . dmc - The coarse mesh 2219 - user - The user context 2220 2221 Output Parameter: 2222 . In - The interpolation matrix 2223 2224 Level: developer 2225 2226 .seealso: DMPlexComputeInterpolatorGeneral(), DMPlexComputeJacobianFEM() 2227 @*/ 2228 PetscErrorCode DMPlexComputeInterpolatorNested(DM dmc, DM dmf, Mat In, void *user) 2229 { 2230 DM_Plex *mesh = (DM_Plex *) dmc->data; 2231 const char *name = "Interpolator"; 2232 PetscDS prob; 2233 PetscFE *feRef; 2234 PetscFV *fvRef; 2235 PetscSection fsection, fglobalSection; 2236 PetscSection csection, cglobalSection; 2237 PetscScalar *elemMat; 2238 PetscInt dim, Nf, f, fieldI, fieldJ, offsetI, offsetJ, cStart, cEnd, c; 2239 PetscInt cTotDim, rTotDim = 0; 2240 PetscErrorCode ierr; 2241 2242 PetscFunctionBegin; 2243 ierr = PetscLogEventBegin(DMPLEX_InterpolatorFEM,dmc,dmf,0,0);CHKERRQ(ierr); 2244 ierr = DMGetDimension(dmf, &dim);CHKERRQ(ierr); 2245 ierr = DMGetLocalSection(dmf, &fsection);CHKERRQ(ierr); 2246 ierr = DMGetGlobalSection(dmf, &fglobalSection);CHKERRQ(ierr); 2247 ierr = DMGetLocalSection(dmc, &csection);CHKERRQ(ierr); 2248 ierr = DMGetGlobalSection(dmc, &cglobalSection);CHKERRQ(ierr); 2249 ierr = PetscSectionGetNumFields(fsection, &Nf);CHKERRQ(ierr); 2250 ierr = DMPlexGetInteriorCellStratum(dmc, &cStart, &cEnd);CHKERRQ(ierr); 2251 ierr = DMGetDS(dmf, &prob);CHKERRQ(ierr); 2252 ierr = PetscCalloc2(Nf,&feRef,Nf,&fvRef);CHKERRQ(ierr); 2253 for (f = 0; f < Nf; ++f) { 2254 PetscObject obj; 2255 PetscClassId id; 2256 PetscInt rNb = 0, Nc = 0; 2257 2258 ierr = PetscDSGetDiscretization(prob, f, &obj);CHKERRQ(ierr); 2259 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 2260 if (id == PETSCFE_CLASSID) { 2261 PetscFE fe = (PetscFE) obj; 2262 2263 ierr = PetscFERefine(fe, &feRef[f]);CHKERRQ(ierr); 2264 ierr = PetscFEGetDimension(feRef[f], &rNb);CHKERRQ(ierr); 2265 ierr = PetscFEGetNumComponents(fe, &Nc);CHKERRQ(ierr); 2266 } else if (id == PETSCFV_CLASSID) { 2267 PetscFV fv = (PetscFV) obj; 2268 PetscDualSpace Q; 2269 2270 ierr = PetscFVRefine(fv, &fvRef[f]);CHKERRQ(ierr); 2271 ierr = PetscFVGetDualSpace(fvRef[f], &Q);CHKERRQ(ierr); 2272 ierr = PetscDualSpaceGetDimension(Q, &rNb);CHKERRQ(ierr); 2273 ierr = PetscFVGetNumComponents(fv, &Nc);CHKERRQ(ierr); 2274 } 2275 rTotDim += rNb; 2276 } 2277 ierr = PetscDSGetTotalDimension(prob, &cTotDim);CHKERRQ(ierr); 2278 ierr = PetscMalloc1(rTotDim*cTotDim,&elemMat);CHKERRQ(ierr); 2279 ierr = PetscArrayzero(elemMat, rTotDim*cTotDim);CHKERRQ(ierr); 2280 for (fieldI = 0, offsetI = 0; fieldI < Nf; ++fieldI) { 2281 PetscDualSpace Qref; 2282 PetscQuadrature f; 2283 const PetscReal *qpoints, *qweights; 2284 PetscReal *points; 2285 PetscInt npoints = 0, Nc, Np, fpdim, i, k, p, d; 2286 2287 /* Compose points from all dual basis functionals */ 2288 if (feRef[fieldI]) { 2289 ierr = PetscFEGetDualSpace(feRef[fieldI], &Qref);CHKERRQ(ierr); 2290 ierr = PetscFEGetNumComponents(feRef[fieldI], &Nc);CHKERRQ(ierr); 2291 } else { 2292 ierr = PetscFVGetDualSpace(fvRef[fieldI], &Qref);CHKERRQ(ierr); 2293 ierr = PetscFVGetNumComponents(fvRef[fieldI], &Nc);CHKERRQ(ierr); 2294 } 2295 ierr = PetscDualSpaceGetDimension(Qref, &fpdim);CHKERRQ(ierr); 2296 for (i = 0; i < fpdim; ++i) { 2297 ierr = PetscDualSpaceGetFunctional(Qref, i, &f);CHKERRQ(ierr); 2298 ierr = PetscQuadratureGetData(f, NULL, NULL, &Np, NULL, NULL);CHKERRQ(ierr); 2299 npoints += Np; 2300 } 2301 ierr = PetscMalloc1(npoints*dim,&points);CHKERRQ(ierr); 2302 for (i = 0, k = 0; i < fpdim; ++i) { 2303 ierr = PetscDualSpaceGetFunctional(Qref, i, &f);CHKERRQ(ierr); 2304 ierr = PetscQuadratureGetData(f, NULL, NULL, &Np, &qpoints, NULL);CHKERRQ(ierr); 2305 for (p = 0; p < Np; ++p, ++k) for (d = 0; d < dim; ++d) points[k*dim+d] = qpoints[p*dim+d]; 2306 } 2307 2308 for (fieldJ = 0, offsetJ = 0; fieldJ < Nf; ++fieldJ) { 2309 PetscObject obj; 2310 PetscClassId id; 2311 PetscReal *B; 2312 PetscInt NcJ = 0, cpdim = 0, j, qNc; 2313 2314 ierr = PetscDSGetDiscretization(prob, fieldJ, &obj);CHKERRQ(ierr); 2315 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 2316 if (id == PETSCFE_CLASSID) { 2317 PetscFE fe = (PetscFE) obj; 2318 2319 /* Evaluate basis at points */ 2320 ierr = PetscFEGetNumComponents(fe, &NcJ);CHKERRQ(ierr); 2321 ierr = PetscFEGetDimension(fe, &cpdim);CHKERRQ(ierr); 2322 /* For now, fields only interpolate themselves */ 2323 if (fieldI == fieldJ) { 2324 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); 2325 ierr = PetscFEGetTabulation(fe, npoints, points, &B, NULL, NULL);CHKERRQ(ierr); 2326 for (i = 0, k = 0; i < fpdim; ++i) { 2327 ierr = PetscDualSpaceGetFunctional(Qref, i, &f);CHKERRQ(ierr); 2328 ierr = PetscQuadratureGetData(f, NULL, &qNc, &Np, NULL, &qweights);CHKERRQ(ierr); 2329 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); 2330 for (p = 0; p < Np; ++p, ++k) { 2331 for (j = 0; j < cpdim; ++j) { 2332 /* 2333 cTotDim: Total columns in element interpolation matrix, sum of number of dual basis functionals in each field 2334 offsetI, offsetJ: Offsets into the larger element interpolation matrix for different fields 2335 fpdim, i, cpdim, j: Dofs for fine and coarse grids, correspond to dual space basis functionals 2336 qNC, Nc, Ncj, c: Number of components in this field 2337 Np, p: Number of quad points in the fine grid functional i 2338 k: i*Np + p, overall point number for the interpolation 2339 */ 2340 for (c = 0; c < Nc; ++c) elemMat[(offsetI + i)*cTotDim + offsetJ + j] += B[k*cpdim*NcJ+j*Nc+c]*qweights[p*qNc+c]; 2341 } 2342 } 2343 } 2344 ierr = PetscFERestoreTabulation(fe, npoints, points, &B, NULL, NULL);CHKERRQ(ierr);CHKERRQ(ierr); 2345 } 2346 } else if (id == PETSCFV_CLASSID) { 2347 PetscFV fv = (PetscFV) obj; 2348 2349 /* Evaluate constant function at points */ 2350 ierr = PetscFVGetNumComponents(fv, &NcJ);CHKERRQ(ierr); 2351 cpdim = 1; 2352 /* For now, fields only interpolate themselves */ 2353 if (fieldI == fieldJ) { 2354 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); 2355 for (i = 0, k = 0; i < fpdim; ++i) { 2356 ierr = PetscDualSpaceGetFunctional(Qref, i, &f);CHKERRQ(ierr); 2357 ierr = PetscQuadratureGetData(f, NULL, &qNc, &Np, NULL, &qweights);CHKERRQ(ierr); 2358 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); 2359 for (p = 0; p < Np; ++p, ++k) { 2360 for (j = 0; j < cpdim; ++j) { 2361 for (c = 0; c < Nc; ++c) elemMat[(offsetI + i)*cTotDim + offsetJ + j] += 1.0*qweights[p*qNc+c]; 2362 } 2363 } 2364 } 2365 } 2366 } 2367 offsetJ += cpdim; 2368 } 2369 offsetI += fpdim; 2370 ierr = PetscFree(points);CHKERRQ(ierr); 2371 } 2372 if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(0, name, rTotDim, cTotDim, elemMat);CHKERRQ(ierr);} 2373 /* Preallocate matrix */ 2374 { 2375 Mat preallocator; 2376 PetscScalar *vals; 2377 PetscInt *cellCIndices, *cellFIndices; 2378 PetscInt locRows, locCols, cell; 2379 2380 ierr = MatGetLocalSize(In, &locRows, &locCols);CHKERRQ(ierr); 2381 ierr = MatCreate(PetscObjectComm((PetscObject) In), &preallocator);CHKERRQ(ierr); 2382 ierr = MatSetType(preallocator, MATPREALLOCATOR);CHKERRQ(ierr); 2383 ierr = MatSetSizes(preallocator, locRows, locCols, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr); 2384 ierr = MatSetUp(preallocator);CHKERRQ(ierr); 2385 ierr = PetscCalloc3(rTotDim*cTotDim, &vals,cTotDim,&cellCIndices,rTotDim,&cellFIndices);CHKERRQ(ierr); 2386 for (cell = cStart; cell < cEnd; ++cell) { 2387 ierr = DMPlexMatGetClosureIndicesRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, cell, cellCIndices, cellFIndices);CHKERRQ(ierr); 2388 ierr = MatSetValues(preallocator, rTotDim, cellFIndices, cTotDim, cellCIndices, vals, INSERT_VALUES);CHKERRQ(ierr); 2389 } 2390 ierr = PetscFree3(vals,cellCIndices,cellFIndices);CHKERRQ(ierr); 2391 ierr = MatAssemblyBegin(preallocator, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 2392 ierr = MatAssemblyEnd(preallocator, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 2393 ierr = MatPreallocatorPreallocate(preallocator, PETSC_TRUE, In);CHKERRQ(ierr); 2394 ierr = MatDestroy(&preallocator);CHKERRQ(ierr); 2395 } 2396 /* Fill matrix */ 2397 ierr = MatZeroEntries(In);CHKERRQ(ierr); 2398 for (c = cStart; c < cEnd; ++c) { 2399 ierr = DMPlexMatSetClosureRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, In, c, elemMat, INSERT_VALUES);CHKERRQ(ierr); 2400 } 2401 for (f = 0; f < Nf; ++f) {ierr = PetscFEDestroy(&feRef[f]);CHKERRQ(ierr);} 2402 ierr = PetscFree2(feRef,fvRef);CHKERRQ(ierr); 2403 ierr = PetscFree(elemMat);CHKERRQ(ierr); 2404 ierr = MatAssemblyBegin(In, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 2405 ierr = MatAssemblyEnd(In, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 2406 if (mesh->printFEM) { 2407 ierr = PetscPrintf(PetscObjectComm((PetscObject)In), "%s:\n", name);CHKERRQ(ierr); 2408 ierr = MatChop(In, 1.0e-10);CHKERRQ(ierr); 2409 ierr = MatView(In, NULL);CHKERRQ(ierr); 2410 } 2411 ierr = PetscLogEventEnd(DMPLEX_InterpolatorFEM,dmc,dmf,0,0);CHKERRQ(ierr); 2412 PetscFunctionReturn(0); 2413 } 2414 2415 PetscErrorCode DMPlexComputeMassMatrixNested(DM dmc, DM dmf, Mat mass, void *user) 2416 { 2417 SETERRQ(PetscObjectComm((PetscObject) dmc), PETSC_ERR_SUP, "Laziness"); 2418 } 2419 2420 /*@ 2421 DMPlexComputeInterpolatorGeneral - Form the local portion of the interpolation matrix I from the coarse DM to a non-nested fine DM. 2422 2423 Input Parameters: 2424 + dmf - The fine mesh 2425 . dmc - The coarse mesh 2426 - user - The user context 2427 2428 Output Parameter: 2429 . In - The interpolation matrix 2430 2431 Level: developer 2432 2433 .seealso: DMPlexComputeInterpolatorNested(), DMPlexComputeJacobianFEM() 2434 @*/ 2435 PetscErrorCode DMPlexComputeInterpolatorGeneral(DM dmc, DM dmf, Mat In, void *user) 2436 { 2437 DM_Plex *mesh = (DM_Plex *) dmf->data; 2438 const char *name = "Interpolator"; 2439 PetscDS prob; 2440 PetscSection fsection, csection, globalFSection, globalCSection; 2441 PetscHSetIJ ht; 2442 PetscLayout rLayout; 2443 PetscInt *dnz, *onz; 2444 PetscInt locRows, rStart, rEnd; 2445 PetscReal *x, *v0, *J, *invJ, detJ; 2446 PetscReal *v0c, *Jc, *invJc, detJc; 2447 PetscScalar *elemMat; 2448 PetscInt dim, Nf, field, totDim, cStart, cEnd, cell, ccell; 2449 PetscErrorCode ierr; 2450 2451 PetscFunctionBegin; 2452 ierr = PetscLogEventBegin(DMPLEX_InterpolatorFEM,dmc,dmf,0,0);CHKERRQ(ierr); 2453 ierr = DMGetCoordinateDim(dmc, &dim);CHKERRQ(ierr); 2454 ierr = DMGetDS(dmc, &prob);CHKERRQ(ierr); 2455 ierr = PetscDSGetWorkspace(prob, &x, NULL, NULL, NULL, NULL);CHKERRQ(ierr); 2456 ierr = PetscDSGetNumFields(prob, &Nf);CHKERRQ(ierr); 2457 ierr = PetscMalloc3(dim,&v0,dim*dim,&J,dim*dim,&invJ);CHKERRQ(ierr); 2458 ierr = PetscMalloc3(dim,&v0c,dim*dim,&Jc,dim*dim,&invJc);CHKERRQ(ierr); 2459 ierr = DMGetLocalSection(dmf, &fsection);CHKERRQ(ierr); 2460 ierr = DMGetGlobalSection(dmf, &globalFSection);CHKERRQ(ierr); 2461 ierr = DMGetLocalSection(dmc, &csection);CHKERRQ(ierr); 2462 ierr = DMGetGlobalSection(dmc, &globalCSection);CHKERRQ(ierr); 2463 ierr = DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd);CHKERRQ(ierr); 2464 ierr = PetscDSGetTotalDimension(prob, &totDim);CHKERRQ(ierr); 2465 ierr = PetscMalloc1(totDim, &elemMat);CHKERRQ(ierr); 2466 2467 ierr = MatGetLocalSize(In, &locRows, NULL);CHKERRQ(ierr); 2468 ierr = PetscLayoutCreate(PetscObjectComm((PetscObject) In), &rLayout);CHKERRQ(ierr); 2469 ierr = PetscLayoutSetLocalSize(rLayout, locRows);CHKERRQ(ierr); 2470 ierr = PetscLayoutSetBlockSize(rLayout, 1);CHKERRQ(ierr); 2471 ierr = PetscLayoutSetUp(rLayout);CHKERRQ(ierr); 2472 ierr = PetscLayoutGetRange(rLayout, &rStart, &rEnd);CHKERRQ(ierr); 2473 ierr = PetscLayoutDestroy(&rLayout);CHKERRQ(ierr); 2474 ierr = PetscCalloc2(locRows,&dnz,locRows,&onz);CHKERRQ(ierr); 2475 ierr = PetscHSetIJCreate(&ht);CHKERRQ(ierr); 2476 for (field = 0; field < Nf; ++field) { 2477 PetscObject obj; 2478 PetscClassId id; 2479 PetscDualSpace Q = NULL; 2480 PetscQuadrature f; 2481 const PetscReal *qpoints; 2482 PetscInt Nc, Np, fpdim, i, d; 2483 2484 ierr = PetscDSGetDiscretization(prob, field, &obj);CHKERRQ(ierr); 2485 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 2486 if (id == PETSCFE_CLASSID) { 2487 PetscFE fe = (PetscFE) obj; 2488 2489 ierr = PetscFEGetDualSpace(fe, &Q);CHKERRQ(ierr); 2490 ierr = PetscFEGetNumComponents(fe, &Nc);CHKERRQ(ierr); 2491 } else if (id == PETSCFV_CLASSID) { 2492 PetscFV fv = (PetscFV) obj; 2493 2494 ierr = PetscFVGetDualSpace(fv, &Q);CHKERRQ(ierr); 2495 Nc = 1; 2496 } 2497 ierr = PetscDualSpaceGetDimension(Q, &fpdim);CHKERRQ(ierr); 2498 /* For each fine grid cell */ 2499 for (cell = cStart; cell < cEnd; ++cell) { 2500 PetscInt *findices, *cindices; 2501 PetscInt numFIndices, numCIndices; 2502 2503 ierr = DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, &numFIndices, &findices, NULL);CHKERRQ(ierr); 2504 ierr = DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ);CHKERRQ(ierr); 2505 if (numFIndices != fpdim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fine indices %D != %D dual basis vecs", numFIndices, fpdim); 2506 for (i = 0; i < fpdim; ++i) { 2507 Vec pointVec; 2508 PetscScalar *pV; 2509 PetscSF coarseCellSF = NULL; 2510 const PetscSFNode *coarseCells; 2511 PetscInt numCoarseCells, q, c; 2512 2513 /* Get points from the dual basis functional quadrature */ 2514 ierr = PetscDualSpaceGetFunctional(Q, i, &f);CHKERRQ(ierr); 2515 ierr = PetscQuadratureGetData(f, NULL, NULL, &Np, &qpoints, NULL);CHKERRQ(ierr); 2516 ierr = VecCreateSeq(PETSC_COMM_SELF, Np*dim, &pointVec);CHKERRQ(ierr); 2517 ierr = VecSetBlockSize(pointVec, dim);CHKERRQ(ierr); 2518 ierr = VecGetArray(pointVec, &pV);CHKERRQ(ierr); 2519 for (q = 0; q < Np; ++q) { 2520 const PetscReal xi0[3] = {-1., -1., -1.}; 2521 2522 /* Transform point to real space */ 2523 CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q*dim], x); 2524 for (d = 0; d < dim; ++d) pV[q*dim+d] = x[d]; 2525 } 2526 ierr = VecRestoreArray(pointVec, &pV);CHKERRQ(ierr); 2527 /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */ 2528 /* OPT: Pack all quad points from fine cell */ 2529 ierr = DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF);CHKERRQ(ierr); 2530 ierr = PetscSFViewFromOptions(coarseCellSF, NULL, "-interp_sf_view");CHKERRQ(ierr); 2531 /* Update preallocation info */ 2532 ierr = PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells);CHKERRQ(ierr); 2533 if (numCoarseCells != Np) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Not all closure points located"); 2534 { 2535 PetscHashIJKey key; 2536 PetscBool missing; 2537 2538 key.i = findices[i]; 2539 if (key.i >= 0) { 2540 /* Get indices for coarse elements */ 2541 for (ccell = 0; ccell < numCoarseCells; ++ccell) { 2542 ierr = DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, &numCIndices, &cindices, NULL);CHKERRQ(ierr); 2543 for (c = 0; c < numCIndices; ++c) { 2544 key.j = cindices[c]; 2545 if (key.j < 0) continue; 2546 ierr = PetscHSetIJQueryAdd(ht, key, &missing);CHKERRQ(ierr); 2547 if (missing) { 2548 if ((key.j >= rStart) && (key.j < rEnd)) ++dnz[key.i-rStart]; 2549 else ++onz[key.i-rStart]; 2550 } 2551 } 2552 ierr = DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, &numCIndices, &cindices, NULL);CHKERRQ(ierr); 2553 } 2554 } 2555 } 2556 ierr = PetscSFDestroy(&coarseCellSF);CHKERRQ(ierr); 2557 ierr = VecDestroy(&pointVec);CHKERRQ(ierr); 2558 } 2559 ierr = DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, &numFIndices, &findices, NULL);CHKERRQ(ierr); 2560 } 2561 } 2562 ierr = PetscHSetIJDestroy(&ht);CHKERRQ(ierr); 2563 ierr = MatXAIJSetPreallocation(In, 1, dnz, onz, NULL, NULL);CHKERRQ(ierr); 2564 ierr = MatSetOption(In, MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr); 2565 ierr = PetscFree2(dnz,onz);CHKERRQ(ierr); 2566 for (field = 0; field < Nf; ++field) { 2567 PetscObject obj; 2568 PetscClassId id; 2569 PetscDualSpace Q = NULL; 2570 PetscQuadrature f; 2571 const PetscReal *qpoints, *qweights; 2572 PetscInt Nc, qNc, Np, fpdim, i, d; 2573 2574 ierr = PetscDSGetDiscretization(prob, field, &obj);CHKERRQ(ierr); 2575 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 2576 if (id == PETSCFE_CLASSID) { 2577 PetscFE fe = (PetscFE) obj; 2578 2579 ierr = PetscFEGetDualSpace(fe, &Q);CHKERRQ(ierr); 2580 ierr = PetscFEGetNumComponents(fe, &Nc);CHKERRQ(ierr); 2581 } else if (id == PETSCFV_CLASSID) { 2582 PetscFV fv = (PetscFV) obj; 2583 2584 ierr = PetscFVGetDualSpace(fv, &Q);CHKERRQ(ierr); 2585 Nc = 1; 2586 } else SETERRQ1(PetscObjectComm((PetscObject)dmc),PETSC_ERR_ARG_WRONG,"Unknown discretization type for field %D",field); 2587 ierr = PetscDualSpaceGetDimension(Q, &fpdim);CHKERRQ(ierr); 2588 /* For each fine grid cell */ 2589 for (cell = cStart; cell < cEnd; ++cell) { 2590 PetscInt *findices, *cindices; 2591 PetscInt numFIndices, numCIndices; 2592 2593 ierr = DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, &numFIndices, &findices, NULL);CHKERRQ(ierr); 2594 ierr = DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ);CHKERRQ(ierr); 2595 if (numFIndices != fpdim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fine indices %D != %D dual basis vecs", numFIndices, fpdim); 2596 for (i = 0; i < fpdim; ++i) { 2597 Vec pointVec; 2598 PetscScalar *pV; 2599 PetscSF coarseCellSF = NULL; 2600 const PetscSFNode *coarseCells; 2601 PetscInt numCoarseCells, cpdim, q, c, j; 2602 2603 /* Get points from the dual basis functional quadrature */ 2604 ierr = PetscDualSpaceGetFunctional(Q, i, &f);CHKERRQ(ierr); 2605 ierr = PetscQuadratureGetData(f, NULL, &qNc, &Np, &qpoints, &qweights);CHKERRQ(ierr); 2606 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); 2607 ierr = VecCreateSeq(PETSC_COMM_SELF, Np*dim, &pointVec);CHKERRQ(ierr); 2608 ierr = VecSetBlockSize(pointVec, dim);CHKERRQ(ierr); 2609 ierr = VecGetArray(pointVec, &pV);CHKERRQ(ierr); 2610 for (q = 0; q < Np; ++q) { 2611 const PetscReal xi0[3] = {-1., -1., -1.}; 2612 2613 /* Transform point to real space */ 2614 CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q*dim], x); 2615 for (d = 0; d < dim; ++d) pV[q*dim+d] = x[d]; 2616 } 2617 ierr = VecRestoreArray(pointVec, &pV);CHKERRQ(ierr); 2618 /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */ 2619 /* OPT: Read this out from preallocation information */ 2620 ierr = DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF);CHKERRQ(ierr); 2621 /* Update preallocation info */ 2622 ierr = PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells);CHKERRQ(ierr); 2623 if (numCoarseCells != Np) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Not all closure points located"); 2624 ierr = VecGetArray(pointVec, &pV);CHKERRQ(ierr); 2625 for (ccell = 0; ccell < numCoarseCells; ++ccell) { 2626 PetscReal pVReal[3]; 2627 const PetscReal xi0[3] = {-1., -1., -1.}; 2628 2629 ierr = DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, &numCIndices, &cindices, NULL);CHKERRQ(ierr); 2630 /* Transform points from real space to coarse reference space */ 2631 ierr = DMPlexComputeCellGeometryFEM(dmc, coarseCells[ccell].index, NULL, v0c, Jc, invJc, &detJc);CHKERRQ(ierr); 2632 for (d = 0; d < dim; ++d) pVReal[d] = PetscRealPart(pV[ccell*dim+d]); 2633 CoordinatesRealToRef(dim, dim, xi0, v0c, invJc, pVReal, x); 2634 2635 if (id == PETSCFE_CLASSID) { 2636 PetscFE fe = (PetscFE) obj; 2637 PetscReal *B; 2638 2639 /* Evaluate coarse basis on contained point */ 2640 ierr = PetscFEGetDimension(fe, &cpdim);CHKERRQ(ierr); 2641 ierr = PetscFEGetTabulation(fe, 1, x, &B, NULL, NULL);CHKERRQ(ierr); 2642 ierr = PetscArrayzero(elemMat, cpdim);CHKERRQ(ierr); 2643 /* Get elemMat entries by multiplying by weight */ 2644 for (j = 0; j < cpdim; ++j) { 2645 for (c = 0; c < Nc; ++c) elemMat[j] += B[j*Nc + c]*qweights[ccell*qNc + c]; 2646 } 2647 ierr = PetscFERestoreTabulation(fe, 1, x, &B, NULL, NULL);CHKERRQ(ierr);CHKERRQ(ierr); 2648 } else { 2649 cpdim = 1; 2650 for (j = 0; j < cpdim; ++j) { 2651 for (c = 0; c < Nc; ++c) elemMat[j] += 1.0*qweights[ccell*qNc + c]; 2652 } 2653 } 2654 /* Update interpolator */ 2655 if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat);CHKERRQ(ierr);} 2656 if (numCIndices != cpdim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %D != %D", numCIndices, cpdim); 2657 ierr = MatSetValues(In, 1, &findices[i], numCIndices, cindices, elemMat, INSERT_VALUES);CHKERRQ(ierr); 2658 ierr = DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, &numCIndices, &cindices, NULL);CHKERRQ(ierr); 2659 } 2660 ierr = VecRestoreArray(pointVec, &pV);CHKERRQ(ierr); 2661 ierr = PetscSFDestroy(&coarseCellSF);CHKERRQ(ierr); 2662 ierr = VecDestroy(&pointVec);CHKERRQ(ierr); 2663 } 2664 ierr = DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, &numFIndices, &findices, NULL);CHKERRQ(ierr); 2665 } 2666 } 2667 ierr = PetscFree3(v0,J,invJ);CHKERRQ(ierr); 2668 ierr = PetscFree3(v0c,Jc,invJc);CHKERRQ(ierr); 2669 ierr = PetscFree(elemMat);CHKERRQ(ierr); 2670 ierr = MatAssemblyBegin(In, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 2671 ierr = MatAssemblyEnd(In, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 2672 ierr = PetscLogEventEnd(DMPLEX_InterpolatorFEM,dmc,dmf,0,0);CHKERRQ(ierr); 2673 PetscFunctionReturn(0); 2674 } 2675 2676 /*@ 2677 DMPlexComputeMassMatrixGeneral - Form the local portion of the mass matrix M from the coarse DM to a non-nested fine DM. 2678 2679 Input Parameters: 2680 + dmf - The fine mesh 2681 . dmc - The coarse mesh 2682 - user - The user context 2683 2684 Output Parameter: 2685 . mass - The mass matrix 2686 2687 Level: developer 2688 2689 .seealso: DMPlexComputeMassMatrixNested(), DMPlexComputeInterpolatorNested(), DMPlexComputeInterpolatorGeneral(), DMPlexComputeJacobianFEM() 2690 @*/ 2691 PetscErrorCode DMPlexComputeMassMatrixGeneral(DM dmc, DM dmf, Mat mass, void *user) 2692 { 2693 DM_Plex *mesh = (DM_Plex *) dmf->data; 2694 const char *name = "Mass Matrix"; 2695 PetscDS prob; 2696 PetscSection fsection, csection, globalFSection, globalCSection; 2697 PetscHSetIJ ht; 2698 PetscLayout rLayout; 2699 PetscInt *dnz, *onz; 2700 PetscInt locRows, rStart, rEnd; 2701 PetscReal *x, *v0, *J, *invJ, detJ; 2702 PetscReal *v0c, *Jc, *invJc, detJc; 2703 PetscScalar *elemMat; 2704 PetscInt dim, Nf, field, totDim, cStart, cEnd, cell, ccell; 2705 PetscErrorCode ierr; 2706 2707 PetscFunctionBegin; 2708 ierr = DMGetCoordinateDim(dmc, &dim);CHKERRQ(ierr); 2709 ierr = DMGetDS(dmc, &prob);CHKERRQ(ierr); 2710 ierr = PetscDSGetWorkspace(prob, &x, NULL, NULL, NULL, NULL);CHKERRQ(ierr); 2711 ierr = PetscDSGetNumFields(prob, &Nf);CHKERRQ(ierr); 2712 ierr = PetscMalloc3(dim,&v0,dim*dim,&J,dim*dim,&invJ);CHKERRQ(ierr); 2713 ierr = PetscMalloc3(dim,&v0c,dim*dim,&Jc,dim*dim,&invJc);CHKERRQ(ierr); 2714 ierr = DMGetLocalSection(dmf, &fsection);CHKERRQ(ierr); 2715 ierr = DMGetGlobalSection(dmf, &globalFSection);CHKERRQ(ierr); 2716 ierr = DMGetLocalSection(dmc, &csection);CHKERRQ(ierr); 2717 ierr = DMGetGlobalSection(dmc, &globalCSection);CHKERRQ(ierr); 2718 ierr = DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd);CHKERRQ(ierr); 2719 ierr = PetscDSGetTotalDimension(prob, &totDim);CHKERRQ(ierr); 2720 ierr = PetscMalloc1(totDim, &elemMat);CHKERRQ(ierr); 2721 2722 ierr = MatGetLocalSize(mass, &locRows, NULL);CHKERRQ(ierr); 2723 ierr = PetscLayoutCreate(PetscObjectComm((PetscObject) mass), &rLayout);CHKERRQ(ierr); 2724 ierr = PetscLayoutSetLocalSize(rLayout, locRows);CHKERRQ(ierr); 2725 ierr = PetscLayoutSetBlockSize(rLayout, 1);CHKERRQ(ierr); 2726 ierr = PetscLayoutSetUp(rLayout);CHKERRQ(ierr); 2727 ierr = PetscLayoutGetRange(rLayout, &rStart, &rEnd);CHKERRQ(ierr); 2728 ierr = PetscLayoutDestroy(&rLayout);CHKERRQ(ierr); 2729 ierr = PetscCalloc2(locRows,&dnz,locRows,&onz);CHKERRQ(ierr); 2730 ierr = PetscHSetIJCreate(&ht);CHKERRQ(ierr); 2731 for (field = 0; field < Nf; ++field) { 2732 PetscObject obj; 2733 PetscClassId id; 2734 PetscQuadrature quad; 2735 const PetscReal *qpoints; 2736 PetscInt Nq, Nc, i, d; 2737 2738 ierr = PetscDSGetDiscretization(prob, field, &obj);CHKERRQ(ierr); 2739 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 2740 if (id == PETSCFE_CLASSID) {ierr = PetscFEGetQuadrature((PetscFE) obj, &quad);CHKERRQ(ierr);} 2741 else {ierr = PetscFVGetQuadrature((PetscFV) obj, &quad);CHKERRQ(ierr);} 2742 ierr = PetscQuadratureGetData(quad, NULL, &Nc, &Nq, &qpoints, NULL);CHKERRQ(ierr); 2743 /* For each fine grid cell */ 2744 for (cell = cStart; cell < cEnd; ++cell) { 2745 Vec pointVec; 2746 PetscScalar *pV; 2747 PetscSF coarseCellSF = NULL; 2748 const PetscSFNode *coarseCells; 2749 PetscInt numCoarseCells, q, c; 2750 PetscInt *findices, *cindices; 2751 PetscInt numFIndices, numCIndices; 2752 2753 ierr = DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, &numFIndices, &findices, NULL);CHKERRQ(ierr); 2754 ierr = DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ);CHKERRQ(ierr); 2755 /* Get points from the quadrature */ 2756 ierr = VecCreateSeq(PETSC_COMM_SELF, Nq*dim, &pointVec);CHKERRQ(ierr); 2757 ierr = VecSetBlockSize(pointVec, dim);CHKERRQ(ierr); 2758 ierr = VecGetArray(pointVec, &pV);CHKERRQ(ierr); 2759 for (q = 0; q < Nq; ++q) { 2760 const PetscReal xi0[3] = {-1., -1., -1.}; 2761 2762 /* Transform point to real space */ 2763 CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q*dim], x); 2764 for (d = 0; d < dim; ++d) pV[q*dim+d] = x[d]; 2765 } 2766 ierr = VecRestoreArray(pointVec, &pV);CHKERRQ(ierr); 2767 /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */ 2768 ierr = DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF);CHKERRQ(ierr); 2769 ierr = PetscSFViewFromOptions(coarseCellSF, NULL, "-interp_sf_view");CHKERRQ(ierr); 2770 /* Update preallocation info */ 2771 ierr = PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells);CHKERRQ(ierr); 2772 if (numCoarseCells != Nq) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Not all closure points located"); 2773 { 2774 PetscHashIJKey key; 2775 PetscBool missing; 2776 2777 for (i = 0; i < numFIndices; ++i) { 2778 key.i = findices[i]; 2779 if (key.i >= 0) { 2780 /* Get indices for coarse elements */ 2781 for (ccell = 0; ccell < numCoarseCells; ++ccell) { 2782 ierr = DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, &numCIndices, &cindices, NULL);CHKERRQ(ierr); 2783 for (c = 0; c < numCIndices; ++c) { 2784 key.j = cindices[c]; 2785 if (key.j < 0) continue; 2786 ierr = PetscHSetIJQueryAdd(ht, key, &missing);CHKERRQ(ierr); 2787 if (missing) { 2788 if ((key.j >= rStart) && (key.j < rEnd)) ++dnz[key.i-rStart]; 2789 else ++onz[key.i-rStart]; 2790 } 2791 } 2792 ierr = DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, &numCIndices, &cindices, NULL);CHKERRQ(ierr); 2793 } 2794 } 2795 } 2796 } 2797 ierr = PetscSFDestroy(&coarseCellSF);CHKERRQ(ierr); 2798 ierr = VecDestroy(&pointVec);CHKERRQ(ierr); 2799 ierr = DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, &numFIndices, &findices, NULL);CHKERRQ(ierr); 2800 } 2801 } 2802 ierr = PetscHSetIJDestroy(&ht);CHKERRQ(ierr); 2803 ierr = MatXAIJSetPreallocation(mass, 1, dnz, onz, NULL, NULL);CHKERRQ(ierr); 2804 ierr = MatSetOption(mass, MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr); 2805 ierr = PetscFree2(dnz,onz);CHKERRQ(ierr); 2806 for (field = 0; field < Nf; ++field) { 2807 PetscObject obj; 2808 PetscClassId id; 2809 PetscQuadrature quad; 2810 PetscReal *Bfine; 2811 const PetscReal *qpoints, *qweights; 2812 PetscInt Nq, Nc, i, d; 2813 2814 ierr = PetscDSGetDiscretization(prob, field, &obj);CHKERRQ(ierr); 2815 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 2816 if (id == PETSCFE_CLASSID) {ierr = PetscFEGetQuadrature((PetscFE) obj, &quad);CHKERRQ(ierr);ierr = PetscFEGetDefaultTabulation((PetscFE) obj, &Bfine, NULL, NULL);CHKERRQ(ierr);} 2817 else {ierr = PetscFVGetQuadrature((PetscFV) obj, &quad);CHKERRQ(ierr);} 2818 ierr = PetscQuadratureGetData(quad, NULL, &Nc, &Nq, &qpoints, &qweights);CHKERRQ(ierr); 2819 /* For each fine grid cell */ 2820 for (cell = cStart; cell < cEnd; ++cell) { 2821 Vec pointVec; 2822 PetscScalar *pV; 2823 PetscSF coarseCellSF = NULL; 2824 const PetscSFNode *coarseCells; 2825 PetscInt numCoarseCells, cpdim, q, c, j; 2826 PetscInt *findices, *cindices; 2827 PetscInt numFIndices, numCIndices; 2828 2829 ierr = DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, &numFIndices, &findices, NULL);CHKERRQ(ierr); 2830 ierr = DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ);CHKERRQ(ierr); 2831 /* Get points from the quadrature */ 2832 ierr = VecCreateSeq(PETSC_COMM_SELF, Nq*dim, &pointVec);CHKERRQ(ierr); 2833 ierr = VecSetBlockSize(pointVec, dim);CHKERRQ(ierr); 2834 ierr = VecGetArray(pointVec, &pV);CHKERRQ(ierr); 2835 for (q = 0; q < Nq; ++q) { 2836 const PetscReal xi0[3] = {-1., -1., -1.}; 2837 2838 /* Transform point to real space */ 2839 CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q*dim], x); 2840 for (d = 0; d < dim; ++d) pV[q*dim+d] = x[d]; 2841 } 2842 ierr = VecRestoreArray(pointVec, &pV);CHKERRQ(ierr); 2843 /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */ 2844 ierr = DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF);CHKERRQ(ierr); 2845 /* Update matrix */ 2846 ierr = PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells);CHKERRQ(ierr); 2847 if (numCoarseCells != Nq) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Not all closure points located"); 2848 ierr = VecGetArray(pointVec, &pV);CHKERRQ(ierr); 2849 for (ccell = 0; ccell < numCoarseCells; ++ccell) { 2850 PetscReal pVReal[3]; 2851 const PetscReal xi0[3] = {-1., -1., -1.}; 2852 2853 2854 ierr = DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, &numCIndices, &cindices, NULL);CHKERRQ(ierr); 2855 /* Transform points from real space to coarse reference space */ 2856 ierr = DMPlexComputeCellGeometryFEM(dmc, coarseCells[ccell].index, NULL, v0c, Jc, invJc, &detJc);CHKERRQ(ierr); 2857 for (d = 0; d < dim; ++d) pVReal[d] = PetscRealPart(pV[ccell*dim+d]); 2858 CoordinatesRealToRef(dim, dim, xi0, v0c, invJc, pVReal, x); 2859 2860 if (id == PETSCFE_CLASSID) { 2861 PetscFE fe = (PetscFE) obj; 2862 PetscReal *B; 2863 2864 /* Evaluate coarse basis on contained point */ 2865 ierr = PetscFEGetDimension(fe, &cpdim);CHKERRQ(ierr); 2866 ierr = PetscFEGetTabulation(fe, 1, x, &B, NULL, NULL);CHKERRQ(ierr); 2867 /* Get elemMat entries by multiplying by weight */ 2868 for (i = 0; i < numFIndices; ++i) { 2869 ierr = PetscArrayzero(elemMat, cpdim);CHKERRQ(ierr); 2870 for (j = 0; j < cpdim; ++j) { 2871 for (c = 0; c < Nc; ++c) elemMat[j] += B[j*Nc + c]*Bfine[(ccell*numFIndices + i)*Nc + c]*qweights[ccell*Nc + c]*detJ; 2872 } 2873 /* Update interpolator */ 2874 if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat);CHKERRQ(ierr);} 2875 if (numCIndices != cpdim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %D != %D", numCIndices, cpdim); 2876 ierr = MatSetValues(mass, 1, &findices[i], numCIndices, cindices, elemMat, ADD_VALUES);CHKERRQ(ierr); 2877 } 2878 ierr = PetscFERestoreTabulation(fe, 1, x, &B, NULL, NULL);CHKERRQ(ierr);CHKERRQ(ierr); 2879 } else { 2880 cpdim = 1; 2881 for (i = 0; i < numFIndices; ++i) { 2882 ierr = PetscArrayzero(elemMat, cpdim);CHKERRQ(ierr); 2883 for (j = 0; j < cpdim; ++j) { 2884 for (c = 0; c < Nc; ++c) elemMat[j] += 1.0*1.0*qweights[ccell*Nc + c]*detJ; 2885 } 2886 /* Update interpolator */ 2887 if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat);CHKERRQ(ierr);} 2888 ierr = PetscPrintf(PETSC_COMM_SELF, "Nq: %D %D Nf: %D %D Nc: %D %D\n", ccell, Nq, i, numFIndices, j, numCIndices);CHKERRQ(ierr); 2889 if (numCIndices != cpdim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %D != %D", numCIndices, cpdim); 2890 ierr = MatSetValues(mass, 1, &findices[i], numCIndices, cindices, elemMat, ADD_VALUES);CHKERRQ(ierr); 2891 } 2892 } 2893 ierr = DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, &numCIndices, &cindices, NULL);CHKERRQ(ierr); 2894 } 2895 ierr = VecRestoreArray(pointVec, &pV);CHKERRQ(ierr); 2896 ierr = PetscSFDestroy(&coarseCellSF);CHKERRQ(ierr); 2897 ierr = VecDestroy(&pointVec);CHKERRQ(ierr); 2898 ierr = DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, &numFIndices, &findices, NULL);CHKERRQ(ierr); 2899 } 2900 } 2901 ierr = PetscFree3(v0,J,invJ);CHKERRQ(ierr); 2902 ierr = PetscFree3(v0c,Jc,invJc);CHKERRQ(ierr); 2903 ierr = PetscFree(elemMat);CHKERRQ(ierr); 2904 ierr = MatAssemblyBegin(mass, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 2905 ierr = MatAssemblyEnd(mass, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 2906 PetscFunctionReturn(0); 2907 } 2908 2909 /*@ 2910 DMPlexComputeInjectorFEM - Compute a mapping from coarse unknowns to fine unknowns 2911 2912 Input Parameters: 2913 + dmc - The coarse mesh 2914 - dmf - The fine mesh 2915 - user - The user context 2916 2917 Output Parameter: 2918 . sc - The mapping 2919 2920 Level: developer 2921 2922 .seealso: DMPlexComputeInterpolatorNested(), DMPlexComputeJacobianFEM() 2923 @*/ 2924 PetscErrorCode DMPlexComputeInjectorFEM(DM dmc, DM dmf, VecScatter *sc, void *user) 2925 { 2926 PetscDS prob; 2927 PetscFE *feRef; 2928 PetscFV *fvRef; 2929 Vec fv, cv; 2930 IS fis, cis; 2931 PetscSection fsection, fglobalSection, csection, cglobalSection; 2932 PetscInt *cmap, *cellCIndices, *cellFIndices, *cindices, *findices; 2933 PetscInt cTotDim, fTotDim = 0, Nf, f, field, cStart, cEnd, c, dim, d, startC, endC, offsetC, offsetF, m; 2934 PetscBool *needAvg; 2935 PetscErrorCode ierr; 2936 2937 PetscFunctionBegin; 2938 ierr = PetscLogEventBegin(DMPLEX_InjectorFEM,dmc,dmf,0,0);CHKERRQ(ierr); 2939 ierr = DMGetDimension(dmf, &dim);CHKERRQ(ierr); 2940 ierr = DMGetLocalSection(dmf, &fsection);CHKERRQ(ierr); 2941 ierr = DMGetGlobalSection(dmf, &fglobalSection);CHKERRQ(ierr); 2942 ierr = DMGetLocalSection(dmc, &csection);CHKERRQ(ierr); 2943 ierr = DMGetGlobalSection(dmc, &cglobalSection);CHKERRQ(ierr); 2944 ierr = PetscSectionGetNumFields(fsection, &Nf);CHKERRQ(ierr); 2945 ierr = DMPlexGetInteriorCellStratum(dmc, &cStart, &cEnd);CHKERRQ(ierr); 2946 ierr = DMGetDS(dmc, &prob);CHKERRQ(ierr); 2947 ierr = PetscCalloc3(Nf,&feRef,Nf,&fvRef,Nf,&needAvg);CHKERRQ(ierr); 2948 for (f = 0; f < Nf; ++f) { 2949 PetscObject obj; 2950 PetscClassId id; 2951 PetscInt fNb = 0, Nc = 0; 2952 2953 ierr = PetscDSGetDiscretization(prob, f, &obj);CHKERRQ(ierr); 2954 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 2955 if (id == PETSCFE_CLASSID) { 2956 PetscFE fe = (PetscFE) obj; 2957 PetscSpace sp; 2958 PetscInt maxDegree; 2959 2960 ierr = PetscFERefine(fe, &feRef[f]);CHKERRQ(ierr); 2961 ierr = PetscFEGetDimension(feRef[f], &fNb);CHKERRQ(ierr); 2962 ierr = PetscFEGetNumComponents(fe, &Nc);CHKERRQ(ierr); 2963 ierr = PetscFEGetBasisSpace(fe, &sp);CHKERRQ(ierr); 2964 ierr = PetscSpaceGetDegree(sp, NULL, &maxDegree);CHKERRQ(ierr); 2965 if (!maxDegree) needAvg[f] = PETSC_TRUE; 2966 } else if (id == PETSCFV_CLASSID) { 2967 PetscFV fv = (PetscFV) obj; 2968 PetscDualSpace Q; 2969 2970 ierr = PetscFVRefine(fv, &fvRef[f]);CHKERRQ(ierr); 2971 ierr = PetscFVGetDualSpace(fvRef[f], &Q);CHKERRQ(ierr); 2972 ierr = PetscDualSpaceGetDimension(Q, &fNb);CHKERRQ(ierr); 2973 ierr = PetscFVGetNumComponents(fv, &Nc);CHKERRQ(ierr); 2974 needAvg[f] = PETSC_TRUE; 2975 } 2976 fTotDim += fNb; 2977 } 2978 ierr = PetscDSGetTotalDimension(prob, &cTotDim);CHKERRQ(ierr); 2979 ierr = PetscMalloc1(cTotDim,&cmap);CHKERRQ(ierr); 2980 for (field = 0, offsetC = 0, offsetF = 0; field < Nf; ++field) { 2981 PetscFE feC; 2982 PetscFV fvC; 2983 PetscDualSpace QF, QC; 2984 PetscInt order = -1, NcF, NcC, fpdim, cpdim; 2985 2986 if (feRef[field]) { 2987 ierr = PetscDSGetDiscretization(prob, field, (PetscObject *) &feC);CHKERRQ(ierr); 2988 ierr = PetscFEGetNumComponents(feC, &NcC);CHKERRQ(ierr); 2989 ierr = PetscFEGetNumComponents(feRef[field], &NcF);CHKERRQ(ierr); 2990 ierr = PetscFEGetDualSpace(feRef[field], &QF);CHKERRQ(ierr); 2991 ierr = PetscDualSpaceGetOrder(QF, &order);CHKERRQ(ierr); 2992 ierr = PetscDualSpaceGetDimension(QF, &fpdim);CHKERRQ(ierr); 2993 ierr = PetscFEGetDualSpace(feC, &QC);CHKERRQ(ierr); 2994 ierr = PetscDualSpaceGetDimension(QC, &cpdim);CHKERRQ(ierr); 2995 } else { 2996 ierr = PetscDSGetDiscretization(prob, field, (PetscObject *) &fvC);CHKERRQ(ierr); 2997 ierr = PetscFVGetNumComponents(fvC, &NcC);CHKERRQ(ierr); 2998 ierr = PetscFVGetNumComponents(fvRef[field], &NcF);CHKERRQ(ierr); 2999 ierr = PetscFVGetDualSpace(fvRef[field], &QF);CHKERRQ(ierr); 3000 ierr = PetscDualSpaceGetDimension(QF, &fpdim);CHKERRQ(ierr); 3001 ierr = PetscFVGetDualSpace(fvC, &QC);CHKERRQ(ierr); 3002 ierr = PetscDualSpaceGetDimension(QC, &cpdim);CHKERRQ(ierr); 3003 } 3004 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); 3005 for (c = 0; c < cpdim; ++c) { 3006 PetscQuadrature cfunc; 3007 const PetscReal *cqpoints, *cqweights; 3008 PetscInt NqcC, NpC; 3009 PetscBool found = PETSC_FALSE; 3010 3011 ierr = PetscDualSpaceGetFunctional(QC, c, &cfunc);CHKERRQ(ierr); 3012 ierr = PetscQuadratureGetData(cfunc, NULL, &NqcC, &NpC, &cqpoints, &cqweights);CHKERRQ(ierr); 3013 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); 3014 if (NpC != 1 && feRef[field]) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Do not know how to do injection for moments"); 3015 for (f = 0; f < fpdim; ++f) { 3016 PetscQuadrature ffunc; 3017 const PetscReal *fqpoints, *fqweights; 3018 PetscReal sum = 0.0; 3019 PetscInt NqcF, NpF; 3020 3021 ierr = PetscDualSpaceGetFunctional(QF, f, &ffunc);CHKERRQ(ierr); 3022 ierr = PetscQuadratureGetData(ffunc, NULL, &NqcF, &NpF, &fqpoints, &fqweights);CHKERRQ(ierr); 3023 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); 3024 if (NpC != NpF) continue; 3025 for (d = 0; d < dim; ++d) sum += PetscAbsReal(cqpoints[d] - fqpoints[d]); 3026 if (sum > 1.0e-9) continue; 3027 for (d = 0; d < NcC; ++d) sum += PetscAbsReal(cqweights[d]*fqweights[d]); 3028 if (sum < 1.0e-9) continue; 3029 cmap[offsetC+c] = offsetF+f; 3030 found = PETSC_TRUE; 3031 break; 3032 } 3033 if (!found) { 3034 /* TODO We really want the average here, but some asshole put VecScatter in the interface */ 3035 if (fvRef[field] || (feRef[field] && order == 0)) { 3036 cmap[offsetC+c] = offsetF+0; 3037 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate matching functional for injection"); 3038 } 3039 } 3040 offsetC += cpdim; 3041 offsetF += fpdim; 3042 } 3043 for (f = 0; f < Nf; ++f) {ierr = PetscFEDestroy(&feRef[f]);CHKERRQ(ierr);ierr = PetscFVDestroy(&fvRef[f]);CHKERRQ(ierr);} 3044 ierr = PetscFree3(feRef,fvRef,needAvg);CHKERRQ(ierr); 3045 3046 ierr = DMGetGlobalVector(dmf, &fv);CHKERRQ(ierr); 3047 ierr = DMGetGlobalVector(dmc, &cv);CHKERRQ(ierr); 3048 ierr = VecGetOwnershipRange(cv, &startC, &endC);CHKERRQ(ierr); 3049 ierr = PetscSectionGetConstrainedStorageSize(cglobalSection, &m);CHKERRQ(ierr); 3050 ierr = PetscMalloc2(cTotDim,&cellCIndices,fTotDim,&cellFIndices);CHKERRQ(ierr); 3051 ierr = PetscMalloc1(m,&cindices);CHKERRQ(ierr); 3052 ierr = PetscMalloc1(m,&findices);CHKERRQ(ierr); 3053 for (d = 0; d < m; ++d) cindices[d] = findices[d] = -1; 3054 for (c = cStart; c < cEnd; ++c) { 3055 ierr = DMPlexMatGetClosureIndicesRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, c, cellCIndices, cellFIndices);CHKERRQ(ierr); 3056 for (d = 0; d < cTotDim; ++d) { 3057 if ((cellCIndices[d] < startC) || (cellCIndices[d] >= endC)) continue; 3058 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]]); 3059 cindices[cellCIndices[d]-startC] = cellCIndices[d]; 3060 findices[cellCIndices[d]-startC] = cellFIndices[cmap[d]]; 3061 } 3062 } 3063 ierr = PetscFree(cmap);CHKERRQ(ierr); 3064 ierr = PetscFree2(cellCIndices,cellFIndices);CHKERRQ(ierr); 3065 3066 ierr = ISCreateGeneral(PETSC_COMM_SELF, m, cindices, PETSC_OWN_POINTER, &cis);CHKERRQ(ierr); 3067 ierr = ISCreateGeneral(PETSC_COMM_SELF, m, findices, PETSC_OWN_POINTER, &fis);CHKERRQ(ierr); 3068 ierr = VecScatterCreate(cv, cis, fv, fis, sc);CHKERRQ(ierr); 3069 ierr = ISDestroy(&cis);CHKERRQ(ierr); 3070 ierr = ISDestroy(&fis);CHKERRQ(ierr); 3071 ierr = DMRestoreGlobalVector(dmf, &fv);CHKERRQ(ierr); 3072 ierr = DMRestoreGlobalVector(dmc, &cv);CHKERRQ(ierr); 3073 ierr = PetscLogEventEnd(DMPLEX_InjectorFEM,dmc,dmf,0,0);CHKERRQ(ierr); 3074 PetscFunctionReturn(0); 3075 } 3076 3077 /*@C 3078 DMPlexGetCellFields - Retrieve the field values values for a chunk of cells 3079 3080 Input Parameters: 3081 + dm - The DM 3082 . cellIS - The cells to include 3083 . locX - A local vector with the solution fields 3084 . locX_t - A local vector with solution field time derivatives, or NULL 3085 - locA - A local vector with auxiliary fields, or NULL 3086 3087 Output Parameters: 3088 + u - The field coefficients 3089 . u_t - The fields derivative coefficients 3090 - a - The auxiliary field coefficients 3091 3092 Level: developer 3093 3094 .seealso: DMPlexGetFaceFields() 3095 @*/ 3096 PetscErrorCode DMPlexGetCellFields(DM dm, IS cellIS, Vec locX, Vec locX_t, Vec locA, PetscScalar **u, PetscScalar **u_t, PetscScalar **a) 3097 { 3098 DM plex, plexA = NULL; 3099 PetscSection section, sectionAux; 3100 PetscDS prob; 3101 const PetscInt *cells; 3102 PetscInt cStart, cEnd, numCells, totDim, totDimAux, c; 3103 PetscErrorCode ierr; 3104 3105 PetscFunctionBegin; 3106 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3107 PetscValidHeaderSpecific(locX, VEC_CLASSID, 4); 3108 if (locX_t) {PetscValidHeaderSpecific(locX_t, VEC_CLASSID, 5);} 3109 if (locA) {PetscValidHeaderSpecific(locA, VEC_CLASSID, 6);} 3110 PetscValidPointer(u, 7); 3111 PetscValidPointer(u_t, 8); 3112 PetscValidPointer(a, 9); 3113 ierr = DMPlexConvertPlex(dm, &plex, PETSC_FALSE);CHKERRQ(ierr); 3114 ierr = ISGetPointRange(cellIS, &cStart, &cEnd, &cells);CHKERRQ(ierr); 3115 ierr = DMGetLocalSection(dm, §ion);CHKERRQ(ierr); 3116 ierr = DMGetCellDS(dm, cStart, &prob);CHKERRQ(ierr); 3117 ierr = PetscDSGetTotalDimension(prob, &totDim);CHKERRQ(ierr); 3118 if (locA) { 3119 DM dmAux; 3120 PetscDS probAux; 3121 3122 ierr = VecGetDM(locA, &dmAux);CHKERRQ(ierr); 3123 ierr = DMPlexConvertPlex(dmAux, &plexA, PETSC_FALSE);CHKERRQ(ierr); 3124 ierr = DMGetLocalSection(dmAux, §ionAux);CHKERRQ(ierr); 3125 ierr = DMGetDS(dmAux, &probAux);CHKERRQ(ierr); 3126 ierr = PetscDSGetTotalDimension(probAux, &totDimAux);CHKERRQ(ierr); 3127 } 3128 numCells = cEnd - cStart; 3129 ierr = DMGetWorkArray(dm, numCells*totDim, MPIU_SCALAR, u);CHKERRQ(ierr); 3130 if (locX_t) {ierr = DMGetWorkArray(dm, numCells*totDim, MPIU_SCALAR, u_t);CHKERRQ(ierr);} else {*u_t = NULL;} 3131 if (locA) {ierr = DMGetWorkArray(dm, numCells*totDimAux, MPIU_SCALAR, a);CHKERRQ(ierr);} else {*a = NULL;} 3132 for (c = cStart; c < cEnd; ++c) { 3133 const PetscInt cell = cells ? cells[c] : c; 3134 const PetscInt cind = c - cStart; 3135 PetscScalar *x = NULL, *x_t = NULL, *ul = *u, *ul_t = *u_t, *al = *a; 3136 PetscInt i; 3137 3138 ierr = DMPlexVecGetClosure(plex, section, locX, cell, NULL, &x);CHKERRQ(ierr); 3139 for (i = 0; i < totDim; ++i) ul[cind*totDim+i] = x[i]; 3140 ierr = DMPlexVecRestoreClosure(plex, section, locX, cell, NULL, &x);CHKERRQ(ierr); 3141 if (locX_t) { 3142 ierr = DMPlexVecGetClosure(plex, section, locX_t, cell, NULL, &x_t);CHKERRQ(ierr); 3143 for (i = 0; i < totDim; ++i) ul_t[cind*totDim+i] = x_t[i]; 3144 ierr = DMPlexVecRestoreClosure(plex, section, locX_t, cell, NULL, &x_t);CHKERRQ(ierr); 3145 } 3146 if (locA) { 3147 PetscInt subcell; 3148 ierr = DMPlexGetAuxiliaryPoint(plex, plexA, cell, &subcell);CHKERRQ(ierr); 3149 ierr = DMPlexVecGetClosure(plexA, sectionAux, locA, subcell, NULL, &x);CHKERRQ(ierr); 3150 for (i = 0; i < totDimAux; ++i) al[cind*totDimAux+i] = x[i]; 3151 ierr = DMPlexVecRestoreClosure(plexA, sectionAux, locA, subcell, NULL, &x);CHKERRQ(ierr); 3152 } 3153 } 3154 ierr = DMDestroy(&plex);CHKERRQ(ierr); 3155 if (locA) {ierr = DMDestroy(&plexA);CHKERRQ(ierr);} 3156 ierr = ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);CHKERRQ(ierr); 3157 PetscFunctionReturn(0); 3158 } 3159 3160 /*@C 3161 DMPlexRestoreCellFields - Restore the field values values for a chunk of cells 3162 3163 Input Parameters: 3164 + dm - The DM 3165 . cellIS - The cells to include 3166 . locX - A local vector with the solution fields 3167 . locX_t - A local vector with solution field time derivatives, or NULL 3168 - locA - A local vector with auxiliary fields, or NULL 3169 3170 Output Parameters: 3171 + u - The field coefficients 3172 . u_t - The fields derivative coefficients 3173 - a - The auxiliary field coefficients 3174 3175 Level: developer 3176 3177 .seealso: DMPlexGetFaceFields() 3178 @*/ 3179 PetscErrorCode DMPlexRestoreCellFields(DM dm, IS cellIS, Vec locX, Vec locX_t, Vec locA, PetscScalar **u, PetscScalar **u_t, PetscScalar **a) 3180 { 3181 PetscErrorCode ierr; 3182 3183 PetscFunctionBegin; 3184 ierr = DMRestoreWorkArray(dm, 0, MPIU_SCALAR, u);CHKERRQ(ierr); 3185 if (locX_t) {ierr = DMRestoreWorkArray(dm, 0, MPIU_SCALAR, u_t);CHKERRQ(ierr);} 3186 if (locA) {ierr = DMRestoreWorkArray(dm, 0, MPIU_SCALAR, a);CHKERRQ(ierr);} 3187 PetscFunctionReturn(0); 3188 } 3189 3190 /*@C 3191 DMPlexGetFaceFields - Retrieve the field values values for a chunk of faces 3192 3193 Input Parameters: 3194 + dm - The DM 3195 . fStart - The first face to include 3196 . fEnd - The first face to exclude 3197 . locX - A local vector with the solution fields 3198 . locX_t - A local vector with solution field time derivatives, or NULL 3199 . faceGeometry - A local vector with face geometry 3200 . cellGeometry - A local vector with cell geometry 3201 - locaGrad - A local vector with field gradients, or NULL 3202 3203 Output Parameters: 3204 + Nface - The number of faces with field values 3205 . uL - The field values at the left side of the face 3206 - uR - The field values at the right side of the face 3207 3208 Level: developer 3209 3210 .seealso: DMPlexGetCellFields() 3211 @*/ 3212 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) 3213 { 3214 DM dmFace, dmCell, dmGrad = NULL; 3215 PetscSection section; 3216 PetscDS prob; 3217 DMLabel ghostLabel; 3218 const PetscScalar *facegeom, *cellgeom, *x, *lgrad; 3219 PetscBool *isFE; 3220 PetscInt dim, Nf, f, Nc, numFaces = fEnd - fStart, iface, face; 3221 PetscErrorCode ierr; 3222 3223 PetscFunctionBegin; 3224 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3225 PetscValidHeaderSpecific(locX, VEC_CLASSID, 4); 3226 if (locX_t) {PetscValidHeaderSpecific(locX_t, VEC_CLASSID, 5);} 3227 PetscValidHeaderSpecific(faceGeometry, VEC_CLASSID, 6); 3228 PetscValidHeaderSpecific(cellGeometry, VEC_CLASSID, 7); 3229 if (locGrad) {PetscValidHeaderSpecific(locGrad, VEC_CLASSID, 8);} 3230 PetscValidPointer(uL, 9); 3231 PetscValidPointer(uR, 10); 3232 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 3233 ierr = DMGetDS(dm, &prob);CHKERRQ(ierr); 3234 ierr = DMGetLocalSection(dm, §ion);CHKERRQ(ierr); 3235 ierr = PetscDSGetNumFields(prob, &Nf);CHKERRQ(ierr); 3236 ierr = PetscDSGetTotalComponents(prob, &Nc);CHKERRQ(ierr); 3237 ierr = PetscMalloc1(Nf, &isFE);CHKERRQ(ierr); 3238 for (f = 0; f < Nf; ++f) { 3239 PetscObject obj; 3240 PetscClassId id; 3241 3242 ierr = PetscDSGetDiscretization(prob, f, &obj);CHKERRQ(ierr); 3243 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 3244 if (id == PETSCFE_CLASSID) {isFE[f] = PETSC_TRUE;} 3245 else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;} 3246 else {isFE[f] = PETSC_FALSE;} 3247 } 3248 ierr = DMGetLabel(dm, "ghost", &ghostLabel);CHKERRQ(ierr); 3249 ierr = VecGetArrayRead(locX, &x);CHKERRQ(ierr); 3250 ierr = VecGetDM(faceGeometry, &dmFace);CHKERRQ(ierr); 3251 ierr = VecGetArrayRead(faceGeometry, &facegeom);CHKERRQ(ierr); 3252 ierr = VecGetDM(cellGeometry, &dmCell);CHKERRQ(ierr); 3253 ierr = VecGetArrayRead(cellGeometry, &cellgeom);CHKERRQ(ierr); 3254 if (locGrad) { 3255 ierr = VecGetDM(locGrad, &dmGrad);CHKERRQ(ierr); 3256 ierr = VecGetArrayRead(locGrad, &lgrad);CHKERRQ(ierr); 3257 } 3258 ierr = DMGetWorkArray(dm, numFaces*Nc, MPIU_SCALAR, uL);CHKERRQ(ierr); 3259 ierr = DMGetWorkArray(dm, numFaces*Nc, MPIU_SCALAR, uR);CHKERRQ(ierr); 3260 /* Right now just eat the extra work for FE (could make a cell loop) */ 3261 for (face = fStart, iface = 0; face < fEnd; ++face) { 3262 const PetscInt *cells; 3263 PetscFVFaceGeom *fg; 3264 PetscFVCellGeom *cgL, *cgR; 3265 PetscScalar *xL, *xR, *gL, *gR; 3266 PetscScalar *uLl = *uL, *uRl = *uR; 3267 PetscInt ghost, nsupp, nchild; 3268 3269 ierr = DMLabelGetValue(ghostLabel, face, &ghost);CHKERRQ(ierr); 3270 ierr = DMPlexGetSupportSize(dm, face, &nsupp);CHKERRQ(ierr); 3271 ierr = DMPlexGetTreeChildren(dm, face, &nchild, NULL);CHKERRQ(ierr); 3272 if (ghost >= 0 || nsupp > 2 || nchild > 0) continue; 3273 ierr = DMPlexPointLocalRead(dmFace, face, facegeom, &fg);CHKERRQ(ierr); 3274 ierr = DMPlexGetSupport(dm, face, &cells);CHKERRQ(ierr); 3275 ierr = DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cgL);CHKERRQ(ierr); 3276 ierr = DMPlexPointLocalRead(dmCell, cells[1], cellgeom, &cgR);CHKERRQ(ierr); 3277 for (f = 0; f < Nf; ++f) { 3278 PetscInt off; 3279 3280 ierr = PetscDSGetComponentOffset(prob, f, &off);CHKERRQ(ierr); 3281 if (isFE[f]) { 3282 const PetscInt *cone; 3283 PetscInt comp, coneSizeL, coneSizeR, faceLocL, faceLocR, ldof, rdof, d; 3284 3285 xL = xR = NULL; 3286 ierr = PetscSectionGetFieldComponents(section, f, &comp);CHKERRQ(ierr); 3287 ierr = DMPlexVecGetClosure(dm, section, locX, cells[0], &ldof, (PetscScalar **) &xL);CHKERRQ(ierr); 3288 ierr = DMPlexVecGetClosure(dm, section, locX, cells[1], &rdof, (PetscScalar **) &xR);CHKERRQ(ierr); 3289 ierr = DMPlexGetCone(dm, cells[0], &cone);CHKERRQ(ierr); 3290 ierr = DMPlexGetConeSize(dm, cells[0], &coneSizeL);CHKERRQ(ierr); 3291 for (faceLocL = 0; faceLocL < coneSizeL; ++faceLocL) if (cone[faceLocL] == face) break; 3292 ierr = DMPlexGetCone(dm, cells[1], &cone);CHKERRQ(ierr); 3293 ierr = DMPlexGetConeSize(dm, cells[1], &coneSizeR);CHKERRQ(ierr); 3294 for (faceLocR = 0; faceLocR < coneSizeR; ++faceLocR) if (cone[faceLocR] == face) break; 3295 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]); 3296 /* Check that FEM field has values in the right cell (sometimes its an FV ghost cell) */ 3297 /* TODO: this is a hack that might not be right for nonconforming */ 3298 if (faceLocL < coneSizeL) { 3299 ierr = PetscFEEvaluateFaceFields_Internal(prob, f, faceLocL, xL, &uLl[iface*Nc+off]);CHKERRQ(ierr); 3300 if (rdof == ldof && faceLocR < coneSizeR) {ierr = PetscFEEvaluateFaceFields_Internal(prob, f, faceLocR, xR, &uRl[iface*Nc+off]);CHKERRQ(ierr);} 3301 else {for(d = 0; d < comp; ++d) uRl[iface*Nc+off+d] = uLl[iface*Nc+off+d];} 3302 } 3303 else { 3304 ierr = PetscFEEvaluateFaceFields_Internal(prob, f, faceLocR, xR, &uRl[iface*Nc+off]);CHKERRQ(ierr); 3305 ierr = PetscSectionGetFieldComponents(section, f, &comp);CHKERRQ(ierr); 3306 for(d = 0; d < comp; ++d) uLl[iface*Nc+off+d] = uRl[iface*Nc+off+d]; 3307 } 3308 ierr = DMPlexVecRestoreClosure(dm, section, locX, cells[0], &ldof, (PetscScalar **) &xL);CHKERRQ(ierr); 3309 ierr = DMPlexVecRestoreClosure(dm, section, locX, cells[1], &rdof, (PetscScalar **) &xR);CHKERRQ(ierr); 3310 } else { 3311 PetscFV fv; 3312 PetscInt numComp, c; 3313 3314 ierr = PetscDSGetDiscretization(prob, f, (PetscObject *) &fv);CHKERRQ(ierr); 3315 ierr = PetscFVGetNumComponents(fv, &numComp);CHKERRQ(ierr); 3316 ierr = DMPlexPointLocalFieldRead(dm, cells[0], f, x, &xL);CHKERRQ(ierr); 3317 ierr = DMPlexPointLocalFieldRead(dm, cells[1], f, x, &xR);CHKERRQ(ierr); 3318 if (dmGrad) { 3319 PetscReal dxL[3], dxR[3]; 3320 3321 ierr = DMPlexPointLocalRead(dmGrad, cells[0], lgrad, &gL);CHKERRQ(ierr); 3322 ierr = DMPlexPointLocalRead(dmGrad, cells[1], lgrad, &gR);CHKERRQ(ierr); 3323 DMPlex_WaxpyD_Internal(dim, -1, cgL->centroid, fg->centroid, dxL); 3324 DMPlex_WaxpyD_Internal(dim, -1, cgR->centroid, fg->centroid, dxR); 3325 for (c = 0; c < numComp; ++c) { 3326 uLl[iface*Nc+off+c] = xL[c] + DMPlex_DotD_Internal(dim, &gL[c*dim], dxL); 3327 uRl[iface*Nc+off+c] = xR[c] + DMPlex_DotD_Internal(dim, &gR[c*dim], dxR); 3328 } 3329 } else { 3330 for (c = 0; c < numComp; ++c) { 3331 uLl[iface*Nc+off+c] = xL[c]; 3332 uRl[iface*Nc+off+c] = xR[c]; 3333 } 3334 } 3335 } 3336 } 3337 ++iface; 3338 } 3339 *Nface = iface; 3340 ierr = VecRestoreArrayRead(locX, &x);CHKERRQ(ierr); 3341 ierr = VecRestoreArrayRead(faceGeometry, &facegeom);CHKERRQ(ierr); 3342 ierr = VecRestoreArrayRead(cellGeometry, &cellgeom);CHKERRQ(ierr); 3343 if (locGrad) { 3344 ierr = VecRestoreArrayRead(locGrad, &lgrad);CHKERRQ(ierr); 3345 } 3346 ierr = PetscFree(isFE);CHKERRQ(ierr); 3347 PetscFunctionReturn(0); 3348 } 3349 3350 /*@C 3351 DMPlexRestoreFaceFields - Restore the field values values for a chunk of faces 3352 3353 Input Parameters: 3354 + dm - The DM 3355 . fStart - The first face to include 3356 . fEnd - The first face to exclude 3357 . locX - A local vector with the solution fields 3358 . locX_t - A local vector with solution field time derivatives, or NULL 3359 . faceGeometry - A local vector with face geometry 3360 . cellGeometry - A local vector with cell geometry 3361 - locaGrad - A local vector with field gradients, or NULL 3362 3363 Output Parameters: 3364 + Nface - The number of faces with field values 3365 . uL - The field values at the left side of the face 3366 - uR - The field values at the right side of the face 3367 3368 Level: developer 3369 3370 .seealso: DMPlexGetFaceFields() 3371 @*/ 3372 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) 3373 { 3374 PetscErrorCode ierr; 3375 3376 PetscFunctionBegin; 3377 ierr = DMRestoreWorkArray(dm, 0, MPIU_SCALAR, uL);CHKERRQ(ierr); 3378 ierr = DMRestoreWorkArray(dm, 0, MPIU_SCALAR, uR);CHKERRQ(ierr); 3379 PetscFunctionReturn(0); 3380 } 3381 3382 /*@C 3383 DMPlexGetFaceGeometry - Retrieve the geometric values for a chunk of faces 3384 3385 Input Parameters: 3386 + dm - The DM 3387 . fStart - The first face to include 3388 . fEnd - The first face to exclude 3389 . faceGeometry - A local vector with face geometry 3390 - cellGeometry - A local vector with cell geometry 3391 3392 Output Parameters: 3393 + Nface - The number of faces with field values 3394 . fgeom - The extract the face centroid and normal 3395 - vol - The cell volume 3396 3397 Level: developer 3398 3399 .seealso: DMPlexGetCellFields() 3400 @*/ 3401 PetscErrorCode DMPlexGetFaceGeometry(DM dm, PetscInt fStart, PetscInt fEnd, Vec faceGeometry, Vec cellGeometry, PetscInt *Nface, PetscFVFaceGeom **fgeom, PetscReal **vol) 3402 { 3403 DM dmFace, dmCell; 3404 DMLabel ghostLabel; 3405 const PetscScalar *facegeom, *cellgeom; 3406 PetscInt dim, numFaces = fEnd - fStart, iface, face; 3407 PetscErrorCode ierr; 3408 3409 PetscFunctionBegin; 3410 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3411 PetscValidHeaderSpecific(faceGeometry, VEC_CLASSID, 4); 3412 PetscValidHeaderSpecific(cellGeometry, VEC_CLASSID, 5); 3413 PetscValidPointer(fgeom, 6); 3414 PetscValidPointer(vol, 7); 3415 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 3416 ierr = DMGetLabel(dm, "ghost", &ghostLabel);CHKERRQ(ierr); 3417 ierr = VecGetDM(faceGeometry, &dmFace);CHKERRQ(ierr); 3418 ierr = VecGetArrayRead(faceGeometry, &facegeom);CHKERRQ(ierr); 3419 ierr = VecGetDM(cellGeometry, &dmCell);CHKERRQ(ierr); 3420 ierr = VecGetArrayRead(cellGeometry, &cellgeom);CHKERRQ(ierr); 3421 ierr = PetscMalloc1(numFaces, fgeom);CHKERRQ(ierr); 3422 ierr = DMGetWorkArray(dm, numFaces*2, MPIU_SCALAR, vol);CHKERRQ(ierr); 3423 for (face = fStart, iface = 0; face < fEnd; ++face) { 3424 const PetscInt *cells; 3425 PetscFVFaceGeom *fg; 3426 PetscFVCellGeom *cgL, *cgR; 3427 PetscFVFaceGeom *fgeoml = *fgeom; 3428 PetscReal *voll = *vol; 3429 PetscInt ghost, d, nchild, nsupp; 3430 3431 ierr = DMLabelGetValue(ghostLabel, face, &ghost);CHKERRQ(ierr); 3432 ierr = DMPlexGetSupportSize(dm, face, &nsupp);CHKERRQ(ierr); 3433 ierr = DMPlexGetTreeChildren(dm, face, &nchild, NULL);CHKERRQ(ierr); 3434 if (ghost >= 0 || nsupp > 2 || nchild > 0) continue; 3435 ierr = DMPlexPointLocalRead(dmFace, face, facegeom, &fg);CHKERRQ(ierr); 3436 ierr = DMPlexGetSupport(dm, face, &cells);CHKERRQ(ierr); 3437 ierr = DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cgL);CHKERRQ(ierr); 3438 ierr = DMPlexPointLocalRead(dmCell, cells[1], cellgeom, &cgR);CHKERRQ(ierr); 3439 for (d = 0; d < dim; ++d) { 3440 fgeoml[iface].centroid[d] = fg->centroid[d]; 3441 fgeoml[iface].normal[d] = fg->normal[d]; 3442 } 3443 voll[iface*2+0] = cgL->volume; 3444 voll[iface*2+1] = cgR->volume; 3445 ++iface; 3446 } 3447 *Nface = iface; 3448 ierr = VecRestoreArrayRead(faceGeometry, &facegeom);CHKERRQ(ierr); 3449 ierr = VecRestoreArrayRead(cellGeometry, &cellgeom);CHKERRQ(ierr); 3450 PetscFunctionReturn(0); 3451 } 3452 3453 /*@C 3454 DMPlexRestoreFaceGeometry - Restore the field values values for a chunk of faces 3455 3456 Input Parameters: 3457 + dm - The DM 3458 . fStart - The first face to include 3459 . fEnd - The first face to exclude 3460 . faceGeometry - A local vector with face geometry 3461 - cellGeometry - A local vector with cell geometry 3462 3463 Output Parameters: 3464 + Nface - The number of faces with field values 3465 . fgeom - The extract the face centroid and normal 3466 - vol - The cell volume 3467 3468 Level: developer 3469 3470 .seealso: DMPlexGetFaceFields() 3471 @*/ 3472 PetscErrorCode DMPlexRestoreFaceGeometry(DM dm, PetscInt fStart, PetscInt fEnd, Vec faceGeometry, Vec cellGeometry, PetscInt *Nface, PetscFVFaceGeom **fgeom, PetscReal **vol) 3473 { 3474 PetscErrorCode ierr; 3475 3476 PetscFunctionBegin; 3477 ierr = PetscFree(*fgeom);CHKERRQ(ierr); 3478 ierr = DMRestoreWorkArray(dm, 0, MPIU_REAL, vol);CHKERRQ(ierr); 3479 PetscFunctionReturn(0); 3480 } 3481 3482 PetscErrorCode DMSNESGetFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom) 3483 { 3484 char composeStr[33] = {0}; 3485 PetscObjectId id; 3486 PetscContainer container; 3487 PetscErrorCode ierr; 3488 3489 PetscFunctionBegin; 3490 ierr = PetscObjectGetId((PetscObject)quad,&id);CHKERRQ(ierr); 3491 ierr = PetscSNPrintf(composeStr, 32, "DMSNESGetFEGeom_%x\n", id);CHKERRQ(ierr); 3492 ierr = PetscObjectQuery((PetscObject) pointIS, composeStr, (PetscObject *) &container);CHKERRQ(ierr); 3493 if (container) { 3494 ierr = PetscContainerGetPointer(container, (void **) geom);CHKERRQ(ierr); 3495 } else { 3496 ierr = DMFieldCreateFEGeom(coordField, pointIS, quad, faceData, geom);CHKERRQ(ierr); 3497 ierr = PetscContainerCreate(PETSC_COMM_SELF,&container);CHKERRQ(ierr); 3498 ierr = PetscContainerSetPointer(container, (void *) *geom);CHKERRQ(ierr); 3499 ierr = PetscContainerSetUserDestroy(container, PetscContainerUserDestroy_PetscFEGeom);CHKERRQ(ierr); 3500 ierr = PetscObjectCompose((PetscObject) pointIS, composeStr, (PetscObject) container);CHKERRQ(ierr); 3501 ierr = PetscContainerDestroy(&container);CHKERRQ(ierr); 3502 } 3503 PetscFunctionReturn(0); 3504 } 3505 3506 PetscErrorCode DMSNESRestoreFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom) 3507 { 3508 PetscFunctionBegin; 3509 *geom = NULL; 3510 PetscFunctionReturn(0); 3511 } 3512 3513 PetscErrorCode DMPlexComputeResidual_Patch_Internal(DM dm, PetscSection section, IS cellIS, PetscReal t, Vec locX, Vec locX_t, Vec locF, void *user) 3514 { 3515 DM_Plex *mesh = (DM_Plex *) dm->data; 3516 const char *name = "Residual"; 3517 DM dmAux = NULL; 3518 DMLabel ghostLabel = NULL; 3519 PetscDS prob = NULL; 3520 PetscDS probAux = NULL; 3521 PetscBool useFEM = PETSC_FALSE; 3522 PetscBool isImplicit = (locX_t || t == PETSC_MIN_REAL) ? PETSC_TRUE : PETSC_FALSE; 3523 DMField coordField = NULL; 3524 Vec locA; 3525 PetscScalar *u = NULL, *u_t, *a, *uL = NULL, *uR = NULL; 3526 IS chunkIS; 3527 const PetscInt *cells; 3528 PetscInt cStart, cEnd, numCells; 3529 PetscInt Nf, f, totDim, totDimAux, numChunks, cellChunkSize, chunk, fStart, fEnd; 3530 PetscInt maxDegree = PETSC_MAX_INT; 3531 PetscQuadrature affineQuad = NULL, *quads = NULL; 3532 PetscFEGeom *affineGeom = NULL, **geoms = NULL; 3533 PetscErrorCode ierr; 3534 3535 PetscFunctionBegin; 3536 ierr = PetscLogEventBegin(DMPLEX_ResidualFEM,dm,0,0,0);CHKERRQ(ierr); 3537 /* FEM+FVM */ 3538 /* 1: Get sizes from dm and dmAux */ 3539 ierr = DMGetLabel(dm, "ghost", &ghostLabel);CHKERRQ(ierr); 3540 ierr = DMGetDS(dm, &prob);CHKERRQ(ierr); 3541 ierr = PetscDSGetNumFields(prob, &Nf);CHKERRQ(ierr); 3542 ierr = PetscDSGetTotalDimension(prob, &totDim);CHKERRQ(ierr); 3543 ierr = PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &locA);CHKERRQ(ierr); 3544 if (locA) { 3545 ierr = VecGetDM(locA, &dmAux);CHKERRQ(ierr); 3546 ierr = DMGetDS(dmAux, &probAux);CHKERRQ(ierr); 3547 ierr = PetscDSGetTotalDimension(probAux, &totDimAux);CHKERRQ(ierr); 3548 } 3549 /* 2: Get geometric data */ 3550 for (f = 0; f < Nf; ++f) { 3551 PetscObject obj; 3552 PetscClassId id; 3553 PetscBool fimp; 3554 3555 ierr = PetscDSGetImplicit(prob, f, &fimp);CHKERRQ(ierr); 3556 if (isImplicit != fimp) continue; 3557 ierr = PetscDSGetDiscretization(prob, f, &obj);CHKERRQ(ierr); 3558 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 3559 if (id == PETSCFE_CLASSID) {useFEM = PETSC_TRUE;} 3560 if (id == PETSCFV_CLASSID) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Use of FVM with PCPATCH not yet implemented"); 3561 } 3562 if (useFEM) { 3563 ierr = DMGetCoordinateField(dm, &coordField);CHKERRQ(ierr); 3564 ierr = DMFieldGetDegree(coordField,cellIS,NULL,&maxDegree);CHKERRQ(ierr); 3565 if (maxDegree <= 1) { 3566 ierr = DMFieldCreateDefaultQuadrature(coordField,cellIS,&affineQuad);CHKERRQ(ierr); 3567 if (affineQuad) { 3568 ierr = DMSNESGetFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom);CHKERRQ(ierr); 3569 } 3570 } else { 3571 ierr = PetscCalloc2(Nf,&quads,Nf,&geoms);CHKERRQ(ierr); 3572 for (f = 0; f < Nf; ++f) { 3573 PetscObject obj; 3574 PetscClassId id; 3575 PetscBool fimp; 3576 3577 ierr = PetscDSGetImplicit(prob, f, &fimp);CHKERRQ(ierr); 3578 if (isImplicit != fimp) continue; 3579 ierr = PetscDSGetDiscretization(prob, f, &obj);CHKERRQ(ierr); 3580 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 3581 if (id == PETSCFE_CLASSID) { 3582 PetscFE fe = (PetscFE) obj; 3583 3584 ierr = PetscFEGetQuadrature(fe, &quads[f]);CHKERRQ(ierr); 3585 ierr = PetscObjectReference((PetscObject)quads[f]);CHKERRQ(ierr); 3586 ierr = DMSNESGetFEGeom(coordField,cellIS,quads[f],PETSC_FALSE,&geoms[f]);CHKERRQ(ierr); 3587 } 3588 } 3589 } 3590 } 3591 /* Loop over chunks */ 3592 ierr = ISGetPointRange(cellIS, &cStart, &cEnd, &cells);CHKERRQ(ierr); 3593 ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr); 3594 if (useFEM) {ierr = ISCreate(PETSC_COMM_SELF, &chunkIS);CHKERRQ(ierr);} 3595 numCells = cEnd - cStart; 3596 numChunks = 1; 3597 cellChunkSize = numCells/numChunks; 3598 numChunks = PetscMin(1,numCells); 3599 for (chunk = 0; chunk < numChunks; ++chunk) { 3600 PetscScalar *elemVec, *fluxL = NULL, *fluxR = NULL; 3601 PetscReal *vol = NULL; 3602 PetscFVFaceGeom *fgeom = NULL; 3603 PetscInt cS = cStart+chunk*cellChunkSize, cE = PetscMin(cS+cellChunkSize, cEnd), numCells = cE - cS, c; 3604 PetscInt numFaces = 0; 3605 3606 /* Extract field coefficients */ 3607 if (useFEM) { 3608 ierr = ISGetPointSubrange(chunkIS, cS, cE, cells);CHKERRQ(ierr); 3609 ierr = DMPlexGetCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a);CHKERRQ(ierr); 3610 ierr = DMGetWorkArray(dm, numCells*totDim, MPIU_SCALAR, &elemVec);CHKERRQ(ierr); 3611 ierr = PetscArrayzero(elemVec, numCells*totDim);CHKERRQ(ierr); 3612 } 3613 /* TODO We will interlace both our field coefficients (u, u_t, uL, uR, etc.) and our output (elemVec, fL, fR). I think this works */ 3614 /* Loop over fields */ 3615 for (f = 0; f < Nf; ++f) { 3616 PetscObject obj; 3617 PetscClassId id; 3618 PetscBool fimp; 3619 PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset; 3620 3621 ierr = PetscDSGetImplicit(prob, f, &fimp);CHKERRQ(ierr); 3622 if (isImplicit != fimp) continue; 3623 ierr = PetscDSGetDiscretization(prob, f, &obj);CHKERRQ(ierr); 3624 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 3625 if (id == PETSCFE_CLASSID) { 3626 PetscFE fe = (PetscFE) obj; 3627 PetscFEGeom *geom = affineGeom ? affineGeom : geoms[f]; 3628 PetscFEGeom *chunkGeom = NULL; 3629 PetscQuadrature quad = affineQuad ? affineQuad : quads[f]; 3630 PetscInt Nq, Nb; 3631 3632 ierr = PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);CHKERRQ(ierr); 3633 ierr = PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL);CHKERRQ(ierr); 3634 ierr = PetscFEGetDimension(fe, &Nb);CHKERRQ(ierr); 3635 blockSize = Nb; 3636 batchSize = numBlocks * blockSize; 3637 ierr = PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);CHKERRQ(ierr); 3638 numChunks = numCells / (numBatches*batchSize); 3639 Ne = numChunks*numBatches*batchSize; 3640 Nr = numCells % (numBatches*batchSize); 3641 offset = numCells - Nr; 3642 /* Integrate FE residual to get elemVec (need fields at quadrature points) */ 3643 /* 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) */ 3644 ierr = PetscFEGeomGetChunk(geom,0,offset,&chunkGeom);CHKERRQ(ierr); 3645 ierr = PetscFEIntegrateResidual(prob, f, Ne, chunkGeom, u, u_t, probAux, a, t, elemVec);CHKERRQ(ierr); 3646 ierr = PetscFEGeomGetChunk(geom,offset,numCells,&chunkGeom);CHKERRQ(ierr); 3647 ierr = PetscFEIntegrateResidual(prob, f, Nr, chunkGeom, &u[offset*totDim], u_t ? &u_t[offset*totDim] : NULL, probAux, &a[offset*totDimAux], t, &elemVec[offset*totDim]);CHKERRQ(ierr); 3648 ierr = PetscFEGeomRestoreChunk(geom,offset,numCells,&chunkGeom);CHKERRQ(ierr); 3649 } else if (id == PETSCFV_CLASSID) { 3650 PetscFV fv = (PetscFV) obj; 3651 3652 Ne = numFaces; 3653 /* Riemann solve over faces (need fields at face centroids) */ 3654 /* We need to evaluate FE fields at those coordinates */ 3655 ierr = PetscFVIntegrateRHSFunction(fv, prob, f, Ne, fgeom, vol, uL, uR, fluxL, fluxR);CHKERRQ(ierr); 3656 } else SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", f); 3657 } 3658 /* Loop over domain */ 3659 if (useFEM) { 3660 /* Add elemVec to locX */ 3661 for (c = cS; c < cE; ++c) { 3662 const PetscInt cell = cells ? cells[c] : c; 3663 const PetscInt cind = c - cStart; 3664 3665 if (mesh->printFEM > 1) {ierr = DMPrintCellVector(cell, name, totDim, &elemVec[cind*totDim]);CHKERRQ(ierr);} 3666 if (ghostLabel) { 3667 PetscInt ghostVal; 3668 3669 ierr = DMLabelGetValue(ghostLabel,cell,&ghostVal);CHKERRQ(ierr); 3670 if (ghostVal > 0) continue; 3671 } 3672 ierr = DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind*totDim], ADD_ALL_VALUES);CHKERRQ(ierr); 3673 } 3674 } 3675 /* Handle time derivative */ 3676 if (locX_t) { 3677 PetscScalar *x_t, *fa; 3678 3679 ierr = VecGetArray(locF, &fa);CHKERRQ(ierr); 3680 ierr = VecGetArray(locX_t, &x_t);CHKERRQ(ierr); 3681 for (f = 0; f < Nf; ++f) { 3682 PetscFV fv; 3683 PetscObject obj; 3684 PetscClassId id; 3685 PetscInt pdim, d; 3686 3687 ierr = PetscDSGetDiscretization(prob, f, &obj);CHKERRQ(ierr); 3688 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 3689 if (id != PETSCFV_CLASSID) continue; 3690 fv = (PetscFV) obj; 3691 ierr = PetscFVGetNumComponents(fv, &pdim);CHKERRQ(ierr); 3692 for (c = cS; c < cE; ++c) { 3693 const PetscInt cell = cells ? cells[c] : c; 3694 PetscScalar *u_t, *r; 3695 3696 if (ghostLabel) { 3697 PetscInt ghostVal; 3698 3699 ierr = DMLabelGetValue(ghostLabel, cell, &ghostVal);CHKERRQ(ierr); 3700 if (ghostVal > 0) continue; 3701 } 3702 ierr = DMPlexPointLocalFieldRead(dm, cell, f, x_t, &u_t);CHKERRQ(ierr); 3703 ierr = DMPlexPointLocalFieldRef(dm, cell, f, fa, &r);CHKERRQ(ierr); 3704 for (d = 0; d < pdim; ++d) r[d] += u_t[d]; 3705 } 3706 } 3707 ierr = VecRestoreArray(locX_t, &x_t);CHKERRQ(ierr); 3708 ierr = VecRestoreArray(locF, &fa);CHKERRQ(ierr); 3709 } 3710 if (useFEM) { 3711 ierr = DMPlexRestoreCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a);CHKERRQ(ierr); 3712 ierr = DMRestoreWorkArray(dm, numCells*totDim, MPIU_SCALAR, &elemVec);CHKERRQ(ierr); 3713 } 3714 } 3715 if (useFEM) {ierr = ISDestroy(&chunkIS);CHKERRQ(ierr);} 3716 ierr = ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);CHKERRQ(ierr); 3717 /* TODO Could include boundary residual here (see DMPlexComputeResidual_Internal) */ 3718 if (useFEM) { 3719 if (maxDegree <= 1) { 3720 ierr = DMSNESRestoreFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom);CHKERRQ(ierr); 3721 ierr = PetscQuadratureDestroy(&affineQuad);CHKERRQ(ierr); 3722 } else { 3723 for (f = 0; f < Nf; ++f) { 3724 ierr = DMSNESRestoreFEGeom(coordField,cellIS,quads[f],PETSC_FALSE,&geoms[f]);CHKERRQ(ierr); 3725 ierr = PetscQuadratureDestroy(&quads[f]);CHKERRQ(ierr); 3726 } 3727 ierr = PetscFree2(quads,geoms);CHKERRQ(ierr); 3728 } 3729 } 3730 ierr = PetscLogEventEnd(DMPLEX_ResidualFEM,dm,0,0,0);CHKERRQ(ierr); 3731 PetscFunctionReturn(0); 3732 } 3733 3734 /* 3735 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 3736 3737 X - The local solution vector 3738 X_t - The local solution time derviative vector, or NULL 3739 */ 3740 PetscErrorCode DMPlexComputeJacobian_Patch_Internal(DM dm, PetscSection section, PetscSection globalSection, IS cellIS, 3741 PetscReal t, PetscReal X_tShift, Vec X, Vec X_t, Mat Jac, Mat JacP, void *ctx) 3742 { 3743 DM_Plex *mesh = (DM_Plex *) dm->data; 3744 const char *name = "Jacobian", *nameP = "JacobianPre"; 3745 DM dmAux = NULL; 3746 PetscDS prob, probAux = NULL; 3747 PetscSection sectionAux = NULL; 3748 Vec A; 3749 DMField coordField; 3750 PetscFEGeom *cgeomFEM; 3751 PetscQuadrature qGeom = NULL; 3752 Mat J = Jac, JP = JacP; 3753 PetscScalar *work, *u = NULL, *u_t = NULL, *a = NULL, *elemMat = NULL, *elemMatP = NULL, *elemMatD = NULL; 3754 PetscBool hasJac, hasPrec, hasDyn, assembleJac, isMatIS, isMatISP, *isFE, hasFV = PETSC_FALSE; 3755 const PetscInt *cells; 3756 PetscInt Nf, fieldI, fieldJ, maxDegree, numCells, cStart, cEnd, numChunks, chunkSize, chunk, totDim, totDimAux = 0, sz, wsz, off = 0, offCell = 0; 3757 PetscErrorCode ierr; 3758 3759 PetscFunctionBegin; 3760 CHKMEMQ; 3761 ierr = ISGetLocalSize(cellIS, &numCells);CHKERRQ(ierr); 3762 ierr = ISGetPointRange(cellIS, &cStart, &cEnd, &cells);CHKERRQ(ierr); 3763 ierr = PetscLogEventBegin(DMPLEX_JacobianFEM,dm,0,0,0);CHKERRQ(ierr); 3764 ierr = DMGetDS(dm, &prob);CHKERRQ(ierr); 3765 ierr = PetscObjectQuery((PetscObject) dm, "dmAux", (PetscObject *) &dmAux);CHKERRQ(ierr); 3766 ierr = PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &A);CHKERRQ(ierr); 3767 if (dmAux) { 3768 ierr = DMGetLocalSection(dmAux, §ionAux);CHKERRQ(ierr); 3769 ierr = DMGetDS(dmAux, &probAux);CHKERRQ(ierr); 3770 } 3771 /* Get flags */ 3772 ierr = PetscDSGetNumFields(prob, &Nf);CHKERRQ(ierr); 3773 ierr = DMGetWorkArray(dm, Nf, MPIU_BOOL, &isFE);CHKERRQ(ierr); 3774 for (fieldI = 0; fieldI < Nf; ++fieldI) { 3775 PetscObject disc; 3776 PetscClassId id; 3777 ierr = PetscDSGetDiscretization(prob, fieldI, &disc);CHKERRQ(ierr); 3778 ierr = PetscObjectGetClassId(disc, &id);CHKERRQ(ierr); 3779 if (id == PETSCFE_CLASSID) {isFE[fieldI] = PETSC_TRUE;} 3780 else if (id == PETSCFV_CLASSID) {hasFV = PETSC_TRUE; isFE[fieldI] = PETSC_FALSE;} 3781 } 3782 ierr = PetscDSHasJacobian(prob, &hasJac);CHKERRQ(ierr); 3783 ierr = PetscDSHasJacobianPreconditioner(prob, &hasPrec);CHKERRQ(ierr); 3784 ierr = PetscDSHasDynamicJacobian(prob, &hasDyn);CHKERRQ(ierr); 3785 assembleJac = hasJac && hasPrec && (Jac != JacP) ? PETSC_TRUE : PETSC_FALSE; 3786 hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE; 3787 ierr = PetscObjectTypeCompare((PetscObject) Jac, MATIS, &isMatIS);CHKERRQ(ierr); 3788 ierr = PetscObjectTypeCompare((PetscObject) JacP, MATIS, &isMatISP);CHKERRQ(ierr); 3789 /* Setup input data and temp arrays (should be DMGetWorkArray) */ 3790 if (isMatISP || isMatISP) {ierr = DMPlexGetSubdomainSection(dm, &globalSection);CHKERRQ(ierr);} 3791 if (isMatIS) {ierr = MatISGetLocalMat(Jac, &J);CHKERRQ(ierr);} 3792 if (isMatISP) {ierr = MatISGetLocalMat(JacP, &JP);CHKERRQ(ierr);} 3793 if (hasFV) {ierr = MatSetOption(JP, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE);CHKERRQ(ierr);} /* No allocated space for FV stuff, so ignore the zero entries */ 3794 ierr = PetscObjectQuery((PetscObject) dm, "dmAux", (PetscObject *) &dmAux);CHKERRQ(ierr); 3795 ierr = PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &A);CHKERRQ(ierr); 3796 ierr = PetscDSGetTotalDimension(prob, &totDim);CHKERRQ(ierr); 3797 if (probAux) {ierr = PetscDSGetTotalDimension(probAux, &totDimAux);CHKERRQ(ierr);} 3798 CHKMEMQ; 3799 /* Compute batch sizes */ 3800 if (isFE[0]) { 3801 PetscFE fe; 3802 PetscQuadrature q; 3803 PetscInt numQuadPoints, numBatches, batchSize, numBlocks, blockSize, Nb; 3804 3805 ierr = PetscDSGetDiscretization(prob, 0, (PetscObject *) &fe);CHKERRQ(ierr); 3806 ierr = PetscFEGetQuadrature(fe, &q);CHKERRQ(ierr); 3807 ierr = PetscQuadratureGetData(q, NULL, NULL, &numQuadPoints, NULL, NULL);CHKERRQ(ierr); 3808 ierr = PetscFEGetDimension(fe, &Nb);CHKERRQ(ierr); 3809 ierr = PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);CHKERRQ(ierr); 3810 blockSize = Nb*numQuadPoints; 3811 batchSize = numBlocks * blockSize; 3812 chunkSize = numBatches * batchSize; 3813 numChunks = numCells / chunkSize + numCells % chunkSize; 3814 ierr = PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);CHKERRQ(ierr); 3815 } else { 3816 chunkSize = numCells; 3817 numChunks = 1; 3818 } 3819 /* Get work space */ 3820 wsz = (((X?1:0) + (X_t?1:0) + (dmAux?1:0))*totDim + ((hasJac?1:0) + (hasPrec?1:0) + (hasDyn?1:0))*totDim*totDim)*chunkSize; 3821 ierr = DMGetWorkArray(dm, wsz, MPIU_SCALAR, &work);CHKERRQ(ierr); 3822 ierr = PetscArrayzero(work, wsz);CHKERRQ(ierr); 3823 off = 0; 3824 u = X ? (sz = chunkSize*totDim, off += sz, work+off-sz) : NULL; 3825 u_t = X_t ? (sz = chunkSize*totDim, off += sz, work+off-sz) : NULL; 3826 a = dmAux ? (sz = chunkSize*totDimAux, off += sz, work+off-sz) : NULL; 3827 elemMat = hasJac ? (sz = chunkSize*totDim*totDim, off += sz, work+off-sz) : NULL; 3828 elemMatP = hasPrec ? (sz = chunkSize*totDim*totDim, off += sz, work+off-sz) : NULL; 3829 elemMatD = hasDyn ? (sz = chunkSize*totDim*totDim, off += sz, work+off-sz) : NULL; 3830 if (off != wsz) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Error is workspace size %D should be %D", off, wsz); 3831 /* Setup geometry */ 3832 ierr = DMGetCoordinateField(dm, &coordField);CHKERRQ(ierr); 3833 ierr = DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree);CHKERRQ(ierr); 3834 if (maxDegree <= 1) {ierr = DMFieldCreateDefaultQuadrature(coordField, cellIS, &qGeom);CHKERRQ(ierr);} 3835 if (!qGeom) { 3836 PetscFE fe; 3837 3838 ierr = PetscDSGetDiscretization(prob, 0, (PetscObject *) &fe);CHKERRQ(ierr); 3839 ierr = PetscFEGetQuadrature(fe, &qGeom);CHKERRQ(ierr); 3840 ierr = PetscObjectReference((PetscObject) qGeom);CHKERRQ(ierr); 3841 } 3842 ierr = DMSNESGetFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM);CHKERRQ(ierr); 3843 /* Compute volume integrals */ 3844 if (assembleJac) {ierr = MatZeroEntries(J);CHKERRQ(ierr);} 3845 ierr = MatZeroEntries(JP);CHKERRQ(ierr); 3846 for (chunk = 0; chunk < numChunks; ++chunk, offCell += chunkSize) { 3847 const PetscInt Ncell = PetscMin(chunkSize, numCells - offCell); 3848 PetscInt c; 3849 3850 /* Extract values */ 3851 for (c = 0; c < Ncell; ++c) { 3852 const PetscInt cell = cells ? cells[c+offCell] : c+offCell; 3853 PetscScalar *x = NULL, *x_t = NULL; 3854 PetscInt i; 3855 3856 if (X) { 3857 ierr = DMPlexVecGetClosure(dm, section, X, cell, NULL, &x);CHKERRQ(ierr); 3858 for (i = 0; i < totDim; ++i) u[c*totDim+i] = x[i]; 3859 ierr = DMPlexVecRestoreClosure(dm, section, X, cell, NULL, &x);CHKERRQ(ierr); 3860 } 3861 if (X_t) { 3862 ierr = DMPlexVecGetClosure(dm, section, X_t, cell, NULL, &x_t);CHKERRQ(ierr); 3863 for (i = 0; i < totDim; ++i) u_t[c*totDim+i] = x_t[i]; 3864 ierr = DMPlexVecRestoreClosure(dm, section, X_t, cell, NULL, &x_t);CHKERRQ(ierr); 3865 } 3866 if (dmAux) { 3867 ierr = DMPlexVecGetClosure(dmAux, sectionAux, A, cell, NULL, &x);CHKERRQ(ierr); 3868 for (i = 0; i < totDimAux; ++i) a[c*totDimAux+i] = x[i]; 3869 ierr = DMPlexVecRestoreClosure(dmAux, sectionAux, A, cell, NULL, &x);CHKERRQ(ierr); 3870 } 3871 } 3872 CHKMEMQ; 3873 for (fieldI = 0; fieldI < Nf; ++fieldI) { 3874 PetscFE fe; 3875 ierr = PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fe);CHKERRQ(ierr); 3876 for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 3877 if (hasJac) {ierr = PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, fieldI, fieldJ, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMat);CHKERRQ(ierr);} 3878 if (hasPrec) {ierr = PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, fieldI, fieldJ, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMatP);CHKERRQ(ierr);} 3879 if (hasDyn) {ierr = PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, fieldI, fieldJ, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMatD);CHKERRQ(ierr);} 3880 } 3881 /* For finite volume, add the identity */ 3882 if (!isFE[fieldI]) { 3883 PetscFV fv; 3884 PetscInt eOffset = 0, Nc, fc, foff; 3885 3886 ierr = PetscDSGetFieldOffset(prob, fieldI, &foff);CHKERRQ(ierr); 3887 ierr = PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fv);CHKERRQ(ierr); 3888 ierr = PetscFVGetNumComponents(fv, &Nc);CHKERRQ(ierr); 3889 for (c = 0; c < chunkSize; ++c, eOffset += totDim*totDim) { 3890 for (fc = 0; fc < Nc; ++fc) { 3891 const PetscInt i = foff + fc; 3892 if (hasJac) {elemMat [eOffset+i*totDim+i] = 1.0;} 3893 if (hasPrec) {elemMatP[eOffset+i*totDim+i] = 1.0;} 3894 } 3895 } 3896 } 3897 } 3898 CHKMEMQ; 3899 /* Add contribution from X_t */ 3900 if (hasDyn) {for (c = 0; c < chunkSize*totDim*totDim; ++c) elemMat[c] += X_tShift*elemMatD[c];} 3901 /* Insert values into matrix */ 3902 for (c = 0; c < Ncell; ++c) { 3903 const PetscInt cell = cells ? cells[c+offCell] : c+offCell; 3904 if (mesh->printFEM > 1) { 3905 if (hasJac) {ierr = DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[(c-cStart)*totDim*totDim]);CHKERRQ(ierr);} 3906 if (hasPrec) {ierr = DMPrintCellMatrix(cell, nameP, totDim, totDim, &elemMatP[(c-cStart)*totDim*totDim]);CHKERRQ(ierr);} 3907 } 3908 if (assembleJac) {ierr = DMPlexMatSetClosure(dm, section, globalSection, Jac, cell, &elemMat[(c-cStart)*totDim*totDim], ADD_VALUES);CHKERRQ(ierr);} 3909 ierr = DMPlexMatSetClosure(dm, section, globalSection, JP, cell, &elemMat[(c-cStart)*totDim*totDim], ADD_VALUES);CHKERRQ(ierr); 3910 } 3911 CHKMEMQ; 3912 } 3913 /* Cleanup */ 3914 ierr = DMSNESRestoreFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM);CHKERRQ(ierr); 3915 ierr = PetscQuadratureDestroy(&qGeom);CHKERRQ(ierr); 3916 if (hasFV) {ierr = MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_FALSE);CHKERRQ(ierr);} 3917 ierr = DMRestoreWorkArray(dm, Nf, MPIU_BOOL, &isFE);CHKERRQ(ierr); 3918 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); 3919 /* Compute boundary integrals */ 3920 /* ierr = DMPlexComputeBdJacobian_Internal(dm, X, X_t, t, X_tShift, Jac, JacP, ctx);CHKERRQ(ierr); */ 3921 /* Assemble matrix */ 3922 if (assembleJac) {ierr = MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);ierr = MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);} 3923 ierr = MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);ierr = MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 3924 ierr = PetscLogEventEnd(DMPLEX_JacobianFEM,dm,0,0,0);CHKERRQ(ierr); 3925 CHKMEMQ; 3926 PetscFunctionReturn(0); 3927 } 3928