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 cds, rds; 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(dmc, &cds);CHKERRQ(ierr); 2252 ierr = DMGetDS(dmf, &rds);CHKERRQ(ierr); 2253 ierr = PetscCalloc2(Nf, &feRef, Nf, &fvRef);CHKERRQ(ierr); 2254 for (f = 0; f < Nf; ++f) { 2255 PetscObject obj; 2256 PetscClassId id; 2257 PetscInt rNb = 0, Nc = 0; 2258 2259 ierr = PetscDSGetDiscretization(rds, f, &obj);CHKERRQ(ierr); 2260 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 2261 if (id == PETSCFE_CLASSID) { 2262 PetscFE fe = (PetscFE) obj; 2263 2264 ierr = PetscFERefine(fe, &feRef[f]);CHKERRQ(ierr); 2265 ierr = PetscFEGetDimension(feRef[f], &rNb);CHKERRQ(ierr); 2266 ierr = PetscFEGetNumComponents(fe, &Nc);CHKERRQ(ierr); 2267 } else if (id == PETSCFV_CLASSID) { 2268 PetscFV fv = (PetscFV) obj; 2269 PetscDualSpace Q; 2270 2271 ierr = PetscFVRefine(fv, &fvRef[f]);CHKERRQ(ierr); 2272 ierr = PetscFVGetDualSpace(fvRef[f], &Q);CHKERRQ(ierr); 2273 ierr = PetscDualSpaceGetDimension(Q, &rNb);CHKERRQ(ierr); 2274 ierr = PetscFVGetNumComponents(fv, &Nc);CHKERRQ(ierr); 2275 } 2276 rTotDim += rNb; 2277 } 2278 ierr = PetscDSGetTotalDimension(cds, &cTotDim);CHKERRQ(ierr); 2279 ierr = PetscMalloc1(rTotDim*cTotDim,&elemMat);CHKERRQ(ierr); 2280 ierr = PetscArrayzero(elemMat, rTotDim*cTotDim);CHKERRQ(ierr); 2281 for (fieldI = 0, offsetI = 0; fieldI < Nf; ++fieldI) { 2282 PetscDualSpace Qref; 2283 PetscQuadrature f; 2284 const PetscReal *qpoints, *qweights; 2285 PetscReal *points; 2286 PetscInt npoints = 0, Nc, Np, fpdim, i, k, p, d; 2287 2288 /* Compose points from all dual basis functionals */ 2289 if (feRef[fieldI]) { 2290 ierr = PetscFEGetDualSpace(feRef[fieldI], &Qref);CHKERRQ(ierr); 2291 ierr = PetscFEGetNumComponents(feRef[fieldI], &Nc);CHKERRQ(ierr); 2292 } else { 2293 ierr = PetscFVGetDualSpace(fvRef[fieldI], &Qref);CHKERRQ(ierr); 2294 ierr = PetscFVGetNumComponents(fvRef[fieldI], &Nc);CHKERRQ(ierr); 2295 } 2296 ierr = PetscDualSpaceGetDimension(Qref, &fpdim);CHKERRQ(ierr); 2297 for (i = 0; i < fpdim; ++i) { 2298 ierr = PetscDualSpaceGetFunctional(Qref, i, &f);CHKERRQ(ierr); 2299 ierr = PetscQuadratureGetData(f, NULL, NULL, &Np, NULL, NULL);CHKERRQ(ierr); 2300 npoints += Np; 2301 } 2302 ierr = PetscMalloc1(npoints*dim,&points);CHKERRQ(ierr); 2303 for (i = 0, k = 0; i < fpdim; ++i) { 2304 ierr = PetscDualSpaceGetFunctional(Qref, i, &f);CHKERRQ(ierr); 2305 ierr = PetscQuadratureGetData(f, NULL, NULL, &Np, &qpoints, NULL);CHKERRQ(ierr); 2306 for (p = 0; p < Np; ++p, ++k) for (d = 0; d < dim; ++d) points[k*dim+d] = qpoints[p*dim+d]; 2307 } 2308 2309 for (fieldJ = 0, offsetJ = 0; fieldJ < Nf; ++fieldJ) { 2310 PetscObject obj; 2311 PetscClassId id; 2312 PetscReal *B; 2313 PetscInt NcJ = 0, cpdim = 0, j, qNc; 2314 2315 ierr = PetscDSGetDiscretization(cds, fieldJ, &obj);CHKERRQ(ierr); 2316 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 2317 if (id == PETSCFE_CLASSID) { 2318 PetscFE fe = (PetscFE) obj; 2319 2320 /* Evaluate basis at points */ 2321 ierr = PetscFEGetNumComponents(fe, &NcJ);CHKERRQ(ierr); 2322 ierr = PetscFEGetDimension(fe, &cpdim);CHKERRQ(ierr); 2323 /* For now, fields only interpolate themselves */ 2324 if (fieldI == fieldJ) { 2325 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); 2326 ierr = PetscFEGetTabulation(fe, npoints, points, &B, NULL, NULL);CHKERRQ(ierr); 2327 for (i = 0, k = 0; i < fpdim; ++i) { 2328 ierr = PetscDualSpaceGetFunctional(Qref, i, &f);CHKERRQ(ierr); 2329 ierr = PetscQuadratureGetData(f, NULL, &qNc, &Np, NULL, &qweights);CHKERRQ(ierr); 2330 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); 2331 for (p = 0; p < Np; ++p, ++k) { 2332 for (j = 0; j < cpdim; ++j) { 2333 /* 2334 cTotDim: Total columns in element interpolation matrix, sum of number of dual basis functionals in each field 2335 offsetI, offsetJ: Offsets into the larger element interpolation matrix for different fields 2336 fpdim, i, cpdim, j: Dofs for fine and coarse grids, correspond to dual space basis functionals 2337 qNC, Nc, Ncj, c: Number of components in this field 2338 Np, p: Number of quad points in the fine grid functional i 2339 k: i*Np + p, overall point number for the interpolation 2340 */ 2341 for (c = 0; c < Nc; ++c) elemMat[(offsetI + i)*cTotDim + offsetJ + j] += B[k*cpdim*NcJ+j*Nc+c]*qweights[p*qNc+c]; 2342 } 2343 } 2344 } 2345 ierr = PetscFERestoreTabulation(fe, npoints, points, &B, NULL, NULL);CHKERRQ(ierr); 2346 } 2347 } else if (id == PETSCFV_CLASSID) { 2348 PetscFV fv = (PetscFV) obj; 2349 2350 /* Evaluate constant function at points */ 2351 ierr = PetscFVGetNumComponents(fv, &NcJ);CHKERRQ(ierr); 2352 cpdim = 1; 2353 /* For now, fields only interpolate themselves */ 2354 if (fieldI == fieldJ) { 2355 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); 2356 for (i = 0, k = 0; i < fpdim; ++i) { 2357 ierr = PetscDualSpaceGetFunctional(Qref, i, &f);CHKERRQ(ierr); 2358 ierr = PetscQuadratureGetData(f, NULL, &qNc, &Np, NULL, &qweights);CHKERRQ(ierr); 2359 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); 2360 for (p = 0; p < Np; ++p, ++k) { 2361 for (j = 0; j < cpdim; ++j) { 2362 for (c = 0; c < Nc; ++c) elemMat[(offsetI + i)*cTotDim + offsetJ + j] += 1.0*qweights[p*qNc+c]; 2363 } 2364 } 2365 } 2366 } 2367 } 2368 offsetJ += cpdim; 2369 } 2370 offsetI += fpdim; 2371 ierr = PetscFree(points);CHKERRQ(ierr); 2372 } 2373 if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(0, name, rTotDim, cTotDim, elemMat);CHKERRQ(ierr);} 2374 /* Preallocate matrix */ 2375 { 2376 Mat preallocator; 2377 PetscScalar *vals; 2378 PetscInt *cellCIndices, *cellFIndices; 2379 PetscInt locRows, locCols, cell; 2380 2381 ierr = MatGetLocalSize(In, &locRows, &locCols);CHKERRQ(ierr); 2382 ierr = MatCreate(PetscObjectComm((PetscObject) In), &preallocator);CHKERRQ(ierr); 2383 ierr = MatSetType(preallocator, MATPREALLOCATOR);CHKERRQ(ierr); 2384 ierr = MatSetSizes(preallocator, locRows, locCols, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr); 2385 ierr = MatSetUp(preallocator);CHKERRQ(ierr); 2386 ierr = PetscCalloc3(rTotDim*cTotDim, &vals,cTotDim,&cellCIndices,rTotDim,&cellFIndices);CHKERRQ(ierr); 2387 for (cell = cStart; cell < cEnd; ++cell) { 2388 ierr = DMPlexMatGetClosureIndicesRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, cell, cellCIndices, cellFIndices);CHKERRQ(ierr); 2389 ierr = MatSetValues(preallocator, rTotDim, cellFIndices, cTotDim, cellCIndices, vals, INSERT_VALUES);CHKERRQ(ierr); 2390 } 2391 ierr = PetscFree3(vals,cellCIndices,cellFIndices);CHKERRQ(ierr); 2392 ierr = MatAssemblyBegin(preallocator, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 2393 ierr = MatAssemblyEnd(preallocator, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 2394 ierr = MatPreallocatorPreallocate(preallocator, PETSC_TRUE, In);CHKERRQ(ierr); 2395 ierr = MatDestroy(&preallocator);CHKERRQ(ierr); 2396 } 2397 /* Fill matrix */ 2398 ierr = MatZeroEntries(In);CHKERRQ(ierr); 2399 for (c = cStart; c < cEnd; ++c) { 2400 ierr = DMPlexMatSetClosureRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, In, c, elemMat, INSERT_VALUES);CHKERRQ(ierr); 2401 } 2402 for (f = 0; f < Nf; ++f) {ierr = PetscFEDestroy(&feRef[f]);CHKERRQ(ierr);} 2403 ierr = PetscFree2(feRef,fvRef);CHKERRQ(ierr); 2404 ierr = PetscFree(elemMat);CHKERRQ(ierr); 2405 ierr = MatAssemblyBegin(In, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 2406 ierr = MatAssemblyEnd(In, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 2407 if (mesh->printFEM) { 2408 ierr = PetscPrintf(PetscObjectComm((PetscObject)In), "%s:\n", name);CHKERRQ(ierr); 2409 ierr = MatChop(In, 1.0e-10);CHKERRQ(ierr); 2410 ierr = MatView(In, NULL);CHKERRQ(ierr); 2411 } 2412 ierr = PetscLogEventEnd(DMPLEX_InterpolatorFEM,dmc,dmf,0,0);CHKERRQ(ierr); 2413 PetscFunctionReturn(0); 2414 } 2415 2416 PetscErrorCode DMPlexComputeMassMatrixNested(DM dmc, DM dmf, Mat mass, void *user) 2417 { 2418 SETERRQ(PetscObjectComm((PetscObject) dmc), PETSC_ERR_SUP, "Laziness"); 2419 } 2420 2421 /*@ 2422 DMPlexComputeInterpolatorGeneral - Form the local portion of the interpolation matrix I from the coarse DM to a non-nested fine DM. 2423 2424 Input Parameters: 2425 + dmf - The fine mesh 2426 . dmc - The coarse mesh 2427 - user - The user context 2428 2429 Output Parameter: 2430 . In - The interpolation matrix 2431 2432 Level: developer 2433 2434 .seealso: DMPlexComputeInterpolatorNested(), DMPlexComputeJacobianFEM() 2435 @*/ 2436 PetscErrorCode DMPlexComputeInterpolatorGeneral(DM dmc, DM dmf, Mat In, void *user) 2437 { 2438 DM_Plex *mesh = (DM_Plex *) dmf->data; 2439 const char *name = "Interpolator"; 2440 PetscDS prob; 2441 PetscSection fsection, csection, globalFSection, globalCSection; 2442 PetscHSetIJ ht; 2443 PetscLayout rLayout; 2444 PetscInt *dnz, *onz; 2445 PetscInt locRows, rStart, rEnd; 2446 PetscReal *x, *v0, *J, *invJ, detJ; 2447 PetscReal *v0c, *Jc, *invJc, detJc; 2448 PetscScalar *elemMat; 2449 PetscInt dim, Nf, field, totDim, cStart, cEnd, cell, ccell; 2450 PetscErrorCode ierr; 2451 2452 PetscFunctionBegin; 2453 ierr = PetscLogEventBegin(DMPLEX_InterpolatorFEM,dmc,dmf,0,0);CHKERRQ(ierr); 2454 ierr = DMGetCoordinateDim(dmc, &dim);CHKERRQ(ierr); 2455 ierr = DMGetDS(dmc, &prob);CHKERRQ(ierr); 2456 ierr = PetscDSGetWorkspace(prob, &x, NULL, NULL, NULL, NULL);CHKERRQ(ierr); 2457 ierr = PetscDSGetNumFields(prob, &Nf);CHKERRQ(ierr); 2458 ierr = PetscMalloc3(dim,&v0,dim*dim,&J,dim*dim,&invJ);CHKERRQ(ierr); 2459 ierr = PetscMalloc3(dim,&v0c,dim*dim,&Jc,dim*dim,&invJc);CHKERRQ(ierr); 2460 ierr = DMGetLocalSection(dmf, &fsection);CHKERRQ(ierr); 2461 ierr = DMGetGlobalSection(dmf, &globalFSection);CHKERRQ(ierr); 2462 ierr = DMGetLocalSection(dmc, &csection);CHKERRQ(ierr); 2463 ierr = DMGetGlobalSection(dmc, &globalCSection);CHKERRQ(ierr); 2464 ierr = DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd);CHKERRQ(ierr); 2465 ierr = PetscDSGetTotalDimension(prob, &totDim);CHKERRQ(ierr); 2466 ierr = PetscMalloc1(totDim, &elemMat);CHKERRQ(ierr); 2467 2468 ierr = MatGetLocalSize(In, &locRows, NULL);CHKERRQ(ierr); 2469 ierr = PetscLayoutCreate(PetscObjectComm((PetscObject) In), &rLayout);CHKERRQ(ierr); 2470 ierr = PetscLayoutSetLocalSize(rLayout, locRows);CHKERRQ(ierr); 2471 ierr = PetscLayoutSetBlockSize(rLayout, 1);CHKERRQ(ierr); 2472 ierr = PetscLayoutSetUp(rLayout);CHKERRQ(ierr); 2473 ierr = PetscLayoutGetRange(rLayout, &rStart, &rEnd);CHKERRQ(ierr); 2474 ierr = PetscLayoutDestroy(&rLayout);CHKERRQ(ierr); 2475 ierr = PetscCalloc2(locRows,&dnz,locRows,&onz);CHKERRQ(ierr); 2476 ierr = PetscHSetIJCreate(&ht);CHKERRQ(ierr); 2477 for (field = 0; field < Nf; ++field) { 2478 PetscObject obj; 2479 PetscClassId id; 2480 PetscDualSpace Q = NULL; 2481 PetscQuadrature f; 2482 const PetscReal *qpoints; 2483 PetscInt Nc, Np, fpdim, i, d; 2484 2485 ierr = PetscDSGetDiscretization(prob, field, &obj);CHKERRQ(ierr); 2486 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 2487 if (id == PETSCFE_CLASSID) { 2488 PetscFE fe = (PetscFE) obj; 2489 2490 ierr = PetscFEGetDualSpace(fe, &Q);CHKERRQ(ierr); 2491 ierr = PetscFEGetNumComponents(fe, &Nc);CHKERRQ(ierr); 2492 } else if (id == PETSCFV_CLASSID) { 2493 PetscFV fv = (PetscFV) obj; 2494 2495 ierr = PetscFVGetDualSpace(fv, &Q);CHKERRQ(ierr); 2496 Nc = 1; 2497 } 2498 ierr = PetscDualSpaceGetDimension(Q, &fpdim);CHKERRQ(ierr); 2499 /* For each fine grid cell */ 2500 for (cell = cStart; cell < cEnd; ++cell) { 2501 PetscInt *findices, *cindices; 2502 PetscInt numFIndices, numCIndices; 2503 2504 ierr = DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, &numFIndices, &findices, NULL);CHKERRQ(ierr); 2505 ierr = DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ);CHKERRQ(ierr); 2506 if (numFIndices != fpdim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fine indices %D != %D dual basis vecs", numFIndices, fpdim); 2507 for (i = 0; i < fpdim; ++i) { 2508 Vec pointVec; 2509 PetscScalar *pV; 2510 PetscSF coarseCellSF = NULL; 2511 const PetscSFNode *coarseCells; 2512 PetscInt numCoarseCells, q, c; 2513 2514 /* Get points from the dual basis functional quadrature */ 2515 ierr = PetscDualSpaceGetFunctional(Q, i, &f);CHKERRQ(ierr); 2516 ierr = PetscQuadratureGetData(f, NULL, NULL, &Np, &qpoints, NULL);CHKERRQ(ierr); 2517 ierr = VecCreateSeq(PETSC_COMM_SELF, Np*dim, &pointVec);CHKERRQ(ierr); 2518 ierr = VecSetBlockSize(pointVec, dim);CHKERRQ(ierr); 2519 ierr = VecGetArray(pointVec, &pV);CHKERRQ(ierr); 2520 for (q = 0; q < Np; ++q) { 2521 const PetscReal xi0[3] = {-1., -1., -1.}; 2522 2523 /* Transform point to real space */ 2524 CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q*dim], x); 2525 for (d = 0; d < dim; ++d) pV[q*dim+d] = x[d]; 2526 } 2527 ierr = VecRestoreArray(pointVec, &pV);CHKERRQ(ierr); 2528 /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */ 2529 /* OPT: Pack all quad points from fine cell */ 2530 ierr = DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF);CHKERRQ(ierr); 2531 ierr = PetscSFViewFromOptions(coarseCellSF, NULL, "-interp_sf_view");CHKERRQ(ierr); 2532 /* Update preallocation info */ 2533 ierr = PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells);CHKERRQ(ierr); 2534 if (numCoarseCells != Np) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Not all closure points located"); 2535 { 2536 PetscHashIJKey key; 2537 PetscBool missing; 2538 2539 key.i = findices[i]; 2540 if (key.i >= 0) { 2541 /* Get indices for coarse elements */ 2542 for (ccell = 0; ccell < numCoarseCells; ++ccell) { 2543 ierr = DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, &numCIndices, &cindices, NULL);CHKERRQ(ierr); 2544 for (c = 0; c < numCIndices; ++c) { 2545 key.j = cindices[c]; 2546 if (key.j < 0) continue; 2547 ierr = PetscHSetIJQueryAdd(ht, key, &missing);CHKERRQ(ierr); 2548 if (missing) { 2549 if ((key.j >= rStart) && (key.j < rEnd)) ++dnz[key.i-rStart]; 2550 else ++onz[key.i-rStart]; 2551 } 2552 } 2553 ierr = DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, &numCIndices, &cindices, NULL);CHKERRQ(ierr); 2554 } 2555 } 2556 } 2557 ierr = PetscSFDestroy(&coarseCellSF);CHKERRQ(ierr); 2558 ierr = VecDestroy(&pointVec);CHKERRQ(ierr); 2559 } 2560 ierr = DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, &numFIndices, &findices, NULL);CHKERRQ(ierr); 2561 } 2562 } 2563 ierr = PetscHSetIJDestroy(&ht);CHKERRQ(ierr); 2564 ierr = MatXAIJSetPreallocation(In, 1, dnz, onz, NULL, NULL);CHKERRQ(ierr); 2565 ierr = MatSetOption(In, MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr); 2566 ierr = PetscFree2(dnz,onz);CHKERRQ(ierr); 2567 for (field = 0; field < Nf; ++field) { 2568 PetscObject obj; 2569 PetscClassId id; 2570 PetscDualSpace Q = NULL; 2571 PetscQuadrature f; 2572 const PetscReal *qpoints, *qweights; 2573 PetscInt Nc, qNc, Np, fpdim, i, d; 2574 2575 ierr = PetscDSGetDiscretization(prob, field, &obj);CHKERRQ(ierr); 2576 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 2577 if (id == PETSCFE_CLASSID) { 2578 PetscFE fe = (PetscFE) obj; 2579 2580 ierr = PetscFEGetDualSpace(fe, &Q);CHKERRQ(ierr); 2581 ierr = PetscFEGetNumComponents(fe, &Nc);CHKERRQ(ierr); 2582 } else if (id == PETSCFV_CLASSID) { 2583 PetscFV fv = (PetscFV) obj; 2584 2585 ierr = PetscFVGetDualSpace(fv, &Q);CHKERRQ(ierr); 2586 Nc = 1; 2587 } else SETERRQ1(PetscObjectComm((PetscObject)dmc),PETSC_ERR_ARG_WRONG,"Unknown discretization type for field %D",field); 2588 ierr = PetscDualSpaceGetDimension(Q, &fpdim);CHKERRQ(ierr); 2589 /* For each fine grid cell */ 2590 for (cell = cStart; cell < cEnd; ++cell) { 2591 PetscInt *findices, *cindices; 2592 PetscInt numFIndices, numCIndices; 2593 2594 ierr = DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, &numFIndices, &findices, NULL);CHKERRQ(ierr); 2595 ierr = DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ);CHKERRQ(ierr); 2596 if (numFIndices != fpdim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Number of fine indices %D != %D dual basis vecs", numFIndices, fpdim); 2597 for (i = 0; i < fpdim; ++i) { 2598 Vec pointVec; 2599 PetscScalar *pV; 2600 PetscSF coarseCellSF = NULL; 2601 const PetscSFNode *coarseCells; 2602 PetscInt numCoarseCells, cpdim, q, c, j; 2603 2604 /* Get points from the dual basis functional quadrature */ 2605 ierr = PetscDualSpaceGetFunctional(Q, i, &f);CHKERRQ(ierr); 2606 ierr = PetscQuadratureGetData(f, NULL, &qNc, &Np, &qpoints, &qweights);CHKERRQ(ierr); 2607 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); 2608 ierr = VecCreateSeq(PETSC_COMM_SELF, Np*dim, &pointVec);CHKERRQ(ierr); 2609 ierr = VecSetBlockSize(pointVec, dim);CHKERRQ(ierr); 2610 ierr = VecGetArray(pointVec, &pV);CHKERRQ(ierr); 2611 for (q = 0; q < Np; ++q) { 2612 const PetscReal xi0[3] = {-1., -1., -1.}; 2613 2614 /* Transform point to real space */ 2615 CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q*dim], x); 2616 for (d = 0; d < dim; ++d) pV[q*dim+d] = x[d]; 2617 } 2618 ierr = VecRestoreArray(pointVec, &pV);CHKERRQ(ierr); 2619 /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */ 2620 /* OPT: Read this out from preallocation information */ 2621 ierr = DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF);CHKERRQ(ierr); 2622 /* Update preallocation info */ 2623 ierr = PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells);CHKERRQ(ierr); 2624 if (numCoarseCells != Np) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Not all closure points located"); 2625 ierr = VecGetArray(pointVec, &pV);CHKERRQ(ierr); 2626 for (ccell = 0; ccell < numCoarseCells; ++ccell) { 2627 PetscReal pVReal[3]; 2628 const PetscReal xi0[3] = {-1., -1., -1.}; 2629 2630 ierr = DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, &numCIndices, &cindices, NULL);CHKERRQ(ierr); 2631 /* Transform points from real space to coarse reference space */ 2632 ierr = DMPlexComputeCellGeometryFEM(dmc, coarseCells[ccell].index, NULL, v0c, Jc, invJc, &detJc);CHKERRQ(ierr); 2633 for (d = 0; d < dim; ++d) pVReal[d] = PetscRealPart(pV[ccell*dim+d]); 2634 CoordinatesRealToRef(dim, dim, xi0, v0c, invJc, pVReal, x); 2635 2636 if (id == PETSCFE_CLASSID) { 2637 PetscFE fe = (PetscFE) obj; 2638 PetscReal *B; 2639 2640 /* Evaluate coarse basis on contained point */ 2641 ierr = PetscFEGetDimension(fe, &cpdim);CHKERRQ(ierr); 2642 ierr = PetscFEGetTabulation(fe, 1, x, &B, NULL, NULL);CHKERRQ(ierr); 2643 ierr = PetscArrayzero(elemMat, cpdim);CHKERRQ(ierr); 2644 /* Get elemMat entries by multiplying by weight */ 2645 for (j = 0; j < cpdim; ++j) { 2646 for (c = 0; c < Nc; ++c) elemMat[j] += B[j*Nc + c]*qweights[ccell*qNc + c]; 2647 } 2648 ierr = PetscFERestoreTabulation(fe, 1, x, &B, NULL, NULL);CHKERRQ(ierr); 2649 } else { 2650 cpdim = 1; 2651 for (j = 0; j < cpdim; ++j) { 2652 for (c = 0; c < Nc; ++c) elemMat[j] += 1.0*qweights[ccell*qNc + c]; 2653 } 2654 } 2655 /* Update interpolator */ 2656 if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat);CHKERRQ(ierr);} 2657 if (numCIndices != cpdim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %D != %D", numCIndices, cpdim); 2658 ierr = MatSetValues(In, 1, &findices[i], numCIndices, cindices, elemMat, INSERT_VALUES);CHKERRQ(ierr); 2659 ierr = DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, &numCIndices, &cindices, NULL);CHKERRQ(ierr); 2660 } 2661 ierr = VecRestoreArray(pointVec, &pV);CHKERRQ(ierr); 2662 ierr = PetscSFDestroy(&coarseCellSF);CHKERRQ(ierr); 2663 ierr = VecDestroy(&pointVec);CHKERRQ(ierr); 2664 } 2665 ierr = DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, &numFIndices, &findices, NULL);CHKERRQ(ierr); 2666 } 2667 } 2668 ierr = PetscFree3(v0,J,invJ);CHKERRQ(ierr); 2669 ierr = PetscFree3(v0c,Jc,invJc);CHKERRQ(ierr); 2670 ierr = PetscFree(elemMat);CHKERRQ(ierr); 2671 ierr = MatAssemblyBegin(In, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 2672 ierr = MatAssemblyEnd(In, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 2673 ierr = PetscLogEventEnd(DMPLEX_InterpolatorFEM,dmc,dmf,0,0);CHKERRQ(ierr); 2674 PetscFunctionReturn(0); 2675 } 2676 2677 /*@ 2678 DMPlexComputeMassMatrixGeneral - Form the local portion of the mass matrix M from the coarse DM to a non-nested fine DM. 2679 2680 Input Parameters: 2681 + dmf - The fine mesh 2682 . dmc - The coarse mesh 2683 - user - The user context 2684 2685 Output Parameter: 2686 . mass - The mass matrix 2687 2688 Level: developer 2689 2690 .seealso: DMPlexComputeMassMatrixNested(), DMPlexComputeInterpolatorNested(), DMPlexComputeInterpolatorGeneral(), DMPlexComputeJacobianFEM() 2691 @*/ 2692 PetscErrorCode DMPlexComputeMassMatrixGeneral(DM dmc, DM dmf, Mat mass, void *user) 2693 { 2694 DM_Plex *mesh = (DM_Plex *) dmf->data; 2695 const char *name = "Mass Matrix"; 2696 PetscDS prob; 2697 PetscSection fsection, csection, globalFSection, globalCSection; 2698 PetscHSetIJ ht; 2699 PetscLayout rLayout; 2700 PetscInt *dnz, *onz; 2701 PetscInt locRows, rStart, rEnd; 2702 PetscReal *x, *v0, *J, *invJ, detJ; 2703 PetscReal *v0c, *Jc, *invJc, detJc; 2704 PetscScalar *elemMat; 2705 PetscInt dim, Nf, field, totDim, cStart, cEnd, cell, ccell; 2706 PetscErrorCode ierr; 2707 2708 PetscFunctionBegin; 2709 ierr = DMGetCoordinateDim(dmc, &dim);CHKERRQ(ierr); 2710 ierr = DMGetDS(dmc, &prob);CHKERRQ(ierr); 2711 ierr = PetscDSGetWorkspace(prob, &x, NULL, NULL, NULL, NULL);CHKERRQ(ierr); 2712 ierr = PetscDSGetNumFields(prob, &Nf);CHKERRQ(ierr); 2713 ierr = PetscMalloc3(dim,&v0,dim*dim,&J,dim*dim,&invJ);CHKERRQ(ierr); 2714 ierr = PetscMalloc3(dim,&v0c,dim*dim,&Jc,dim*dim,&invJc);CHKERRQ(ierr); 2715 ierr = DMGetLocalSection(dmf, &fsection);CHKERRQ(ierr); 2716 ierr = DMGetGlobalSection(dmf, &globalFSection);CHKERRQ(ierr); 2717 ierr = DMGetLocalSection(dmc, &csection);CHKERRQ(ierr); 2718 ierr = DMGetGlobalSection(dmc, &globalCSection);CHKERRQ(ierr); 2719 ierr = DMPlexGetHeightStratum(dmf, 0, &cStart, &cEnd);CHKERRQ(ierr); 2720 ierr = PetscDSGetTotalDimension(prob, &totDim);CHKERRQ(ierr); 2721 ierr = PetscMalloc1(totDim, &elemMat);CHKERRQ(ierr); 2722 2723 ierr = MatGetLocalSize(mass, &locRows, NULL);CHKERRQ(ierr); 2724 ierr = PetscLayoutCreate(PetscObjectComm((PetscObject) mass), &rLayout);CHKERRQ(ierr); 2725 ierr = PetscLayoutSetLocalSize(rLayout, locRows);CHKERRQ(ierr); 2726 ierr = PetscLayoutSetBlockSize(rLayout, 1);CHKERRQ(ierr); 2727 ierr = PetscLayoutSetUp(rLayout);CHKERRQ(ierr); 2728 ierr = PetscLayoutGetRange(rLayout, &rStart, &rEnd);CHKERRQ(ierr); 2729 ierr = PetscLayoutDestroy(&rLayout);CHKERRQ(ierr); 2730 ierr = PetscCalloc2(locRows,&dnz,locRows,&onz);CHKERRQ(ierr); 2731 ierr = PetscHSetIJCreate(&ht);CHKERRQ(ierr); 2732 for (field = 0; field < Nf; ++field) { 2733 PetscObject obj; 2734 PetscClassId id; 2735 PetscQuadrature quad; 2736 const PetscReal *qpoints; 2737 PetscInt Nq, Nc, i, d; 2738 2739 ierr = PetscDSGetDiscretization(prob, field, &obj);CHKERRQ(ierr); 2740 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 2741 if (id == PETSCFE_CLASSID) {ierr = PetscFEGetQuadrature((PetscFE) obj, &quad);CHKERRQ(ierr);} 2742 else {ierr = PetscFVGetQuadrature((PetscFV) obj, &quad);CHKERRQ(ierr);} 2743 ierr = PetscQuadratureGetData(quad, NULL, &Nc, &Nq, &qpoints, NULL);CHKERRQ(ierr); 2744 /* For each fine grid cell */ 2745 for (cell = cStart; cell < cEnd; ++cell) { 2746 Vec pointVec; 2747 PetscScalar *pV; 2748 PetscSF coarseCellSF = NULL; 2749 const PetscSFNode *coarseCells; 2750 PetscInt numCoarseCells, q, c; 2751 PetscInt *findices, *cindices; 2752 PetscInt numFIndices, numCIndices; 2753 2754 ierr = DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, &numFIndices, &findices, NULL);CHKERRQ(ierr); 2755 ierr = DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ);CHKERRQ(ierr); 2756 /* Get points from the quadrature */ 2757 ierr = VecCreateSeq(PETSC_COMM_SELF, Nq*dim, &pointVec);CHKERRQ(ierr); 2758 ierr = VecSetBlockSize(pointVec, dim);CHKERRQ(ierr); 2759 ierr = VecGetArray(pointVec, &pV);CHKERRQ(ierr); 2760 for (q = 0; q < Nq; ++q) { 2761 const PetscReal xi0[3] = {-1., -1., -1.}; 2762 2763 /* Transform point to real space */ 2764 CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q*dim], x); 2765 for (d = 0; d < dim; ++d) pV[q*dim+d] = x[d]; 2766 } 2767 ierr = VecRestoreArray(pointVec, &pV);CHKERRQ(ierr); 2768 /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */ 2769 ierr = DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF);CHKERRQ(ierr); 2770 ierr = PetscSFViewFromOptions(coarseCellSF, NULL, "-interp_sf_view");CHKERRQ(ierr); 2771 /* Update preallocation info */ 2772 ierr = PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells);CHKERRQ(ierr); 2773 if (numCoarseCells != Nq) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Not all closure points located"); 2774 { 2775 PetscHashIJKey key; 2776 PetscBool missing; 2777 2778 for (i = 0; i < numFIndices; ++i) { 2779 key.i = findices[i]; 2780 if (key.i >= 0) { 2781 /* Get indices for coarse elements */ 2782 for (ccell = 0; ccell < numCoarseCells; ++ccell) { 2783 ierr = DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, &numCIndices, &cindices, NULL);CHKERRQ(ierr); 2784 for (c = 0; c < numCIndices; ++c) { 2785 key.j = cindices[c]; 2786 if (key.j < 0) continue; 2787 ierr = PetscHSetIJQueryAdd(ht, key, &missing);CHKERRQ(ierr); 2788 if (missing) { 2789 if ((key.j >= rStart) && (key.j < rEnd)) ++dnz[key.i-rStart]; 2790 else ++onz[key.i-rStart]; 2791 } 2792 } 2793 ierr = DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, &numCIndices, &cindices, NULL);CHKERRQ(ierr); 2794 } 2795 } 2796 } 2797 } 2798 ierr = PetscSFDestroy(&coarseCellSF);CHKERRQ(ierr); 2799 ierr = VecDestroy(&pointVec);CHKERRQ(ierr); 2800 ierr = DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, &numFIndices, &findices, NULL);CHKERRQ(ierr); 2801 } 2802 } 2803 ierr = PetscHSetIJDestroy(&ht);CHKERRQ(ierr); 2804 ierr = MatXAIJSetPreallocation(mass, 1, dnz, onz, NULL, NULL);CHKERRQ(ierr); 2805 ierr = MatSetOption(mass, MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr); 2806 ierr = PetscFree2(dnz,onz);CHKERRQ(ierr); 2807 for (field = 0; field < Nf; ++field) { 2808 PetscObject obj; 2809 PetscClassId id; 2810 PetscQuadrature quad; 2811 PetscReal *Bfine; 2812 const PetscReal *qpoints, *qweights; 2813 PetscInt Nq, Nc, i, d; 2814 2815 ierr = PetscDSGetDiscretization(prob, field, &obj);CHKERRQ(ierr); 2816 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 2817 if (id == PETSCFE_CLASSID) {ierr = PetscFEGetQuadrature((PetscFE) obj, &quad);CHKERRQ(ierr);ierr = PetscFEGetDefaultTabulation((PetscFE) obj, &Bfine, NULL, NULL);CHKERRQ(ierr);} 2818 else {ierr = PetscFVGetQuadrature((PetscFV) obj, &quad);CHKERRQ(ierr);} 2819 ierr = PetscQuadratureGetData(quad, NULL, &Nc, &Nq, &qpoints, &qweights);CHKERRQ(ierr); 2820 /* For each fine grid cell */ 2821 for (cell = cStart; cell < cEnd; ++cell) { 2822 Vec pointVec; 2823 PetscScalar *pV; 2824 PetscSF coarseCellSF = NULL; 2825 const PetscSFNode *coarseCells; 2826 PetscInt numCoarseCells, cpdim, q, c, j; 2827 PetscInt *findices, *cindices; 2828 PetscInt numFIndices, numCIndices; 2829 2830 ierr = DMPlexGetClosureIndices(dmf, fsection, globalFSection, cell, &numFIndices, &findices, NULL);CHKERRQ(ierr); 2831 ierr = DMPlexComputeCellGeometryFEM(dmf, cell, NULL, v0, J, invJ, &detJ);CHKERRQ(ierr); 2832 /* Get points from the quadrature */ 2833 ierr = VecCreateSeq(PETSC_COMM_SELF, Nq*dim, &pointVec);CHKERRQ(ierr); 2834 ierr = VecSetBlockSize(pointVec, dim);CHKERRQ(ierr); 2835 ierr = VecGetArray(pointVec, &pV);CHKERRQ(ierr); 2836 for (q = 0; q < Nq; ++q) { 2837 const PetscReal xi0[3] = {-1., -1., -1.}; 2838 2839 /* Transform point to real space */ 2840 CoordinatesRefToReal(dim, dim, xi0, v0, J, &qpoints[q*dim], x); 2841 for (d = 0; d < dim; ++d) pV[q*dim+d] = x[d]; 2842 } 2843 ierr = VecRestoreArray(pointVec, &pV);CHKERRQ(ierr); 2844 /* Get set of coarse cells that overlap points (would like to group points by coarse cell) */ 2845 ierr = DMLocatePoints(dmc, pointVec, DM_POINTLOCATION_NEAREST, &coarseCellSF);CHKERRQ(ierr); 2846 /* Update matrix */ 2847 ierr = PetscSFGetGraph(coarseCellSF, NULL, &numCoarseCells, NULL, &coarseCells);CHKERRQ(ierr); 2848 if (numCoarseCells != Nq) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Not all closure points located"); 2849 ierr = VecGetArray(pointVec, &pV);CHKERRQ(ierr); 2850 for (ccell = 0; ccell < numCoarseCells; ++ccell) { 2851 PetscReal pVReal[3]; 2852 const PetscReal xi0[3] = {-1., -1., -1.}; 2853 2854 2855 ierr = DMPlexGetClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, &numCIndices, &cindices, NULL);CHKERRQ(ierr); 2856 /* Transform points from real space to coarse reference space */ 2857 ierr = DMPlexComputeCellGeometryFEM(dmc, coarseCells[ccell].index, NULL, v0c, Jc, invJc, &detJc);CHKERRQ(ierr); 2858 for (d = 0; d < dim; ++d) pVReal[d] = PetscRealPart(pV[ccell*dim+d]); 2859 CoordinatesRealToRef(dim, dim, xi0, v0c, invJc, pVReal, x); 2860 2861 if (id == PETSCFE_CLASSID) { 2862 PetscFE fe = (PetscFE) obj; 2863 PetscReal *B; 2864 2865 /* Evaluate coarse basis on contained point */ 2866 ierr = PetscFEGetDimension(fe, &cpdim);CHKERRQ(ierr); 2867 ierr = PetscFEGetTabulation(fe, 1, x, &B, NULL, NULL);CHKERRQ(ierr); 2868 /* Get elemMat entries by multiplying by weight */ 2869 for (i = 0; i < numFIndices; ++i) { 2870 ierr = PetscArrayzero(elemMat, cpdim);CHKERRQ(ierr); 2871 for (j = 0; j < cpdim; ++j) { 2872 for (c = 0; c < Nc; ++c) elemMat[j] += B[j*Nc + c]*Bfine[(ccell*numFIndices + i)*Nc + c]*qweights[ccell*Nc + c]*detJ; 2873 } 2874 /* Update interpolator */ 2875 if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat);CHKERRQ(ierr);} 2876 if (numCIndices != cpdim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %D != %D", numCIndices, cpdim); 2877 ierr = MatSetValues(mass, 1, &findices[i], numCIndices, cindices, elemMat, ADD_VALUES);CHKERRQ(ierr); 2878 } 2879 ierr = PetscFERestoreTabulation(fe, 1, x, &B, NULL, NULL);CHKERRQ(ierr); 2880 } else { 2881 cpdim = 1; 2882 for (i = 0; i < numFIndices; ++i) { 2883 ierr = PetscArrayzero(elemMat, cpdim);CHKERRQ(ierr); 2884 for (j = 0; j < cpdim; ++j) { 2885 for (c = 0; c < Nc; ++c) elemMat[j] += 1.0*1.0*qweights[ccell*Nc + c]*detJ; 2886 } 2887 /* Update interpolator */ 2888 if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(cell, name, 1, numCIndices, elemMat);CHKERRQ(ierr);} 2889 ierr = PetscPrintf(PETSC_COMM_SELF, "Nq: %D %D Nf: %D %D Nc: %D %D\n", ccell, Nq, i, numFIndices, j, numCIndices);CHKERRQ(ierr); 2890 if (numCIndices != cpdim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of element matrix columns %D != %D", numCIndices, cpdim); 2891 ierr = MatSetValues(mass, 1, &findices[i], numCIndices, cindices, elemMat, ADD_VALUES);CHKERRQ(ierr); 2892 } 2893 } 2894 ierr = DMPlexRestoreClosureIndices(dmc, csection, globalCSection, coarseCells[ccell].index, &numCIndices, &cindices, NULL);CHKERRQ(ierr); 2895 } 2896 ierr = VecRestoreArray(pointVec, &pV);CHKERRQ(ierr); 2897 ierr = PetscSFDestroy(&coarseCellSF);CHKERRQ(ierr); 2898 ierr = VecDestroy(&pointVec);CHKERRQ(ierr); 2899 ierr = DMPlexRestoreClosureIndices(dmf, fsection, globalFSection, cell, &numFIndices, &findices, NULL);CHKERRQ(ierr); 2900 } 2901 } 2902 ierr = PetscFree3(v0,J,invJ);CHKERRQ(ierr); 2903 ierr = PetscFree3(v0c,Jc,invJc);CHKERRQ(ierr); 2904 ierr = PetscFree(elemMat);CHKERRQ(ierr); 2905 ierr = MatAssemblyBegin(mass, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 2906 ierr = MatAssemblyEnd(mass, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 2907 PetscFunctionReturn(0); 2908 } 2909 2910 /*@ 2911 DMPlexComputeInjectorFEM - Compute a mapping from coarse unknowns to fine unknowns 2912 2913 Input Parameters: 2914 + dmc - The coarse mesh 2915 - dmf - The fine mesh 2916 - user - The user context 2917 2918 Output Parameter: 2919 . sc - The mapping 2920 2921 Level: developer 2922 2923 .seealso: DMPlexComputeInterpolatorNested(), DMPlexComputeJacobianFEM() 2924 @*/ 2925 PetscErrorCode DMPlexComputeInjectorFEM(DM dmc, DM dmf, VecScatter *sc, void *user) 2926 { 2927 PetscDS prob; 2928 PetscFE *feRef; 2929 PetscFV *fvRef; 2930 Vec fv, cv; 2931 IS fis, cis; 2932 PetscSection fsection, fglobalSection, csection, cglobalSection; 2933 PetscInt *cmap, *cellCIndices, *cellFIndices, *cindices, *findices; 2934 PetscInt cTotDim, fTotDim = 0, Nf, f, field, cStart, cEnd, c, dim, d, startC, endC, offsetC, offsetF, m; 2935 PetscBool *needAvg; 2936 PetscErrorCode ierr; 2937 2938 PetscFunctionBegin; 2939 ierr = PetscLogEventBegin(DMPLEX_InjectorFEM,dmc,dmf,0,0);CHKERRQ(ierr); 2940 ierr = DMGetDimension(dmf, &dim);CHKERRQ(ierr); 2941 ierr = DMGetLocalSection(dmf, &fsection);CHKERRQ(ierr); 2942 ierr = DMGetGlobalSection(dmf, &fglobalSection);CHKERRQ(ierr); 2943 ierr = DMGetLocalSection(dmc, &csection);CHKERRQ(ierr); 2944 ierr = DMGetGlobalSection(dmc, &cglobalSection);CHKERRQ(ierr); 2945 ierr = PetscSectionGetNumFields(fsection, &Nf);CHKERRQ(ierr); 2946 ierr = DMPlexGetInteriorCellStratum(dmc, &cStart, &cEnd);CHKERRQ(ierr); 2947 ierr = DMGetDS(dmc, &prob);CHKERRQ(ierr); 2948 ierr = PetscCalloc3(Nf,&feRef,Nf,&fvRef,Nf,&needAvg);CHKERRQ(ierr); 2949 for (f = 0; f < Nf; ++f) { 2950 PetscObject obj; 2951 PetscClassId id; 2952 PetscInt fNb = 0, Nc = 0; 2953 2954 ierr = PetscDSGetDiscretization(prob, f, &obj);CHKERRQ(ierr); 2955 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 2956 if (id == PETSCFE_CLASSID) { 2957 PetscFE fe = (PetscFE) obj; 2958 PetscSpace sp; 2959 PetscInt maxDegree; 2960 2961 ierr = PetscFERefine(fe, &feRef[f]);CHKERRQ(ierr); 2962 ierr = PetscFEGetDimension(feRef[f], &fNb);CHKERRQ(ierr); 2963 ierr = PetscFEGetNumComponents(fe, &Nc);CHKERRQ(ierr); 2964 ierr = PetscFEGetBasisSpace(fe, &sp);CHKERRQ(ierr); 2965 ierr = PetscSpaceGetDegree(sp, NULL, &maxDegree);CHKERRQ(ierr); 2966 if (!maxDegree) needAvg[f] = PETSC_TRUE; 2967 } else if (id == PETSCFV_CLASSID) { 2968 PetscFV fv = (PetscFV) obj; 2969 PetscDualSpace Q; 2970 2971 ierr = PetscFVRefine(fv, &fvRef[f]);CHKERRQ(ierr); 2972 ierr = PetscFVGetDualSpace(fvRef[f], &Q);CHKERRQ(ierr); 2973 ierr = PetscDualSpaceGetDimension(Q, &fNb);CHKERRQ(ierr); 2974 ierr = PetscFVGetNumComponents(fv, &Nc);CHKERRQ(ierr); 2975 needAvg[f] = PETSC_TRUE; 2976 } 2977 fTotDim += fNb; 2978 } 2979 ierr = PetscDSGetTotalDimension(prob, &cTotDim);CHKERRQ(ierr); 2980 ierr = PetscMalloc1(cTotDim,&cmap);CHKERRQ(ierr); 2981 for (field = 0, offsetC = 0, offsetF = 0; field < Nf; ++field) { 2982 PetscFE feC; 2983 PetscFV fvC; 2984 PetscDualSpace QF, QC; 2985 PetscInt order = -1, NcF, NcC, fpdim, cpdim; 2986 2987 if (feRef[field]) { 2988 ierr = PetscDSGetDiscretization(prob, field, (PetscObject *) &feC);CHKERRQ(ierr); 2989 ierr = PetscFEGetNumComponents(feC, &NcC);CHKERRQ(ierr); 2990 ierr = PetscFEGetNumComponents(feRef[field], &NcF);CHKERRQ(ierr); 2991 ierr = PetscFEGetDualSpace(feRef[field], &QF);CHKERRQ(ierr); 2992 ierr = PetscDualSpaceGetOrder(QF, &order);CHKERRQ(ierr); 2993 ierr = PetscDualSpaceGetDimension(QF, &fpdim);CHKERRQ(ierr); 2994 ierr = PetscFEGetDualSpace(feC, &QC);CHKERRQ(ierr); 2995 ierr = PetscDualSpaceGetDimension(QC, &cpdim);CHKERRQ(ierr); 2996 } else { 2997 ierr = PetscDSGetDiscretization(prob, field, (PetscObject *) &fvC);CHKERRQ(ierr); 2998 ierr = PetscFVGetNumComponents(fvC, &NcC);CHKERRQ(ierr); 2999 ierr = PetscFVGetNumComponents(fvRef[field], &NcF);CHKERRQ(ierr); 3000 ierr = PetscFVGetDualSpace(fvRef[field], &QF);CHKERRQ(ierr); 3001 ierr = PetscDualSpaceGetDimension(QF, &fpdim);CHKERRQ(ierr); 3002 ierr = PetscFVGetDualSpace(fvC, &QC);CHKERRQ(ierr); 3003 ierr = PetscDualSpaceGetDimension(QC, &cpdim);CHKERRQ(ierr); 3004 } 3005 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); 3006 for (c = 0; c < cpdim; ++c) { 3007 PetscQuadrature cfunc; 3008 const PetscReal *cqpoints, *cqweights; 3009 PetscInt NqcC, NpC; 3010 PetscBool found = PETSC_FALSE; 3011 3012 ierr = PetscDualSpaceGetFunctional(QC, c, &cfunc);CHKERRQ(ierr); 3013 ierr = PetscQuadratureGetData(cfunc, NULL, &NqcC, &NpC, &cqpoints, &cqweights);CHKERRQ(ierr); 3014 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); 3015 if (NpC != 1 && feRef[field]) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Do not know how to do injection for moments"); 3016 for (f = 0; f < fpdim; ++f) { 3017 PetscQuadrature ffunc; 3018 const PetscReal *fqpoints, *fqweights; 3019 PetscReal sum = 0.0; 3020 PetscInt NqcF, NpF; 3021 3022 ierr = PetscDualSpaceGetFunctional(QF, f, &ffunc);CHKERRQ(ierr); 3023 ierr = PetscQuadratureGetData(ffunc, NULL, &NqcF, &NpF, &fqpoints, &fqweights);CHKERRQ(ierr); 3024 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); 3025 if (NpC != NpF) continue; 3026 for (d = 0; d < dim; ++d) sum += PetscAbsReal(cqpoints[d] - fqpoints[d]); 3027 if (sum > 1.0e-9) continue; 3028 for (d = 0; d < NcC; ++d) sum += PetscAbsReal(cqweights[d]*fqweights[d]); 3029 if (sum < 1.0e-9) continue; 3030 cmap[offsetC+c] = offsetF+f; 3031 found = PETSC_TRUE; 3032 break; 3033 } 3034 if (!found) { 3035 /* TODO We really want the average here, but some asshole put VecScatter in the interface */ 3036 if (fvRef[field] || (feRef[field] && order == 0)) { 3037 cmap[offsetC+c] = offsetF+0; 3038 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not locate matching functional for injection"); 3039 } 3040 } 3041 offsetC += cpdim; 3042 offsetF += fpdim; 3043 } 3044 for (f = 0; f < Nf; ++f) {ierr = PetscFEDestroy(&feRef[f]);CHKERRQ(ierr);ierr = PetscFVDestroy(&fvRef[f]);CHKERRQ(ierr);} 3045 ierr = PetscFree3(feRef,fvRef,needAvg);CHKERRQ(ierr); 3046 3047 ierr = DMGetGlobalVector(dmf, &fv);CHKERRQ(ierr); 3048 ierr = DMGetGlobalVector(dmc, &cv);CHKERRQ(ierr); 3049 ierr = VecGetOwnershipRange(cv, &startC, &endC);CHKERRQ(ierr); 3050 ierr = PetscSectionGetConstrainedStorageSize(cglobalSection, &m);CHKERRQ(ierr); 3051 ierr = PetscMalloc2(cTotDim,&cellCIndices,fTotDim,&cellFIndices);CHKERRQ(ierr); 3052 ierr = PetscMalloc1(m,&cindices);CHKERRQ(ierr); 3053 ierr = PetscMalloc1(m,&findices);CHKERRQ(ierr); 3054 for (d = 0; d < m; ++d) cindices[d] = findices[d] = -1; 3055 for (c = cStart; c < cEnd; ++c) { 3056 ierr = DMPlexMatGetClosureIndicesRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, c, cellCIndices, cellFIndices);CHKERRQ(ierr); 3057 for (d = 0; d < cTotDim; ++d) { 3058 if ((cellCIndices[d] < startC) || (cellCIndices[d] >= endC)) continue; 3059 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]]); 3060 cindices[cellCIndices[d]-startC] = cellCIndices[d]; 3061 findices[cellCIndices[d]-startC] = cellFIndices[cmap[d]]; 3062 } 3063 } 3064 ierr = PetscFree(cmap);CHKERRQ(ierr); 3065 ierr = PetscFree2(cellCIndices,cellFIndices);CHKERRQ(ierr); 3066 3067 ierr = ISCreateGeneral(PETSC_COMM_SELF, m, cindices, PETSC_OWN_POINTER, &cis);CHKERRQ(ierr); 3068 ierr = ISCreateGeneral(PETSC_COMM_SELF, m, findices, PETSC_OWN_POINTER, &fis);CHKERRQ(ierr); 3069 ierr = VecScatterCreate(cv, cis, fv, fis, sc);CHKERRQ(ierr); 3070 ierr = ISDestroy(&cis);CHKERRQ(ierr); 3071 ierr = ISDestroy(&fis);CHKERRQ(ierr); 3072 ierr = DMRestoreGlobalVector(dmf, &fv);CHKERRQ(ierr); 3073 ierr = DMRestoreGlobalVector(dmc, &cv);CHKERRQ(ierr); 3074 ierr = PetscLogEventEnd(DMPLEX_InjectorFEM,dmc,dmf,0,0);CHKERRQ(ierr); 3075 PetscFunctionReturn(0); 3076 } 3077 3078 /*@C 3079 DMPlexGetCellFields - Retrieve the field values values for a chunk of cells 3080 3081 Input Parameters: 3082 + dm - The DM 3083 . cellIS - The cells to include 3084 . locX - A local vector with the solution fields 3085 . locX_t - A local vector with solution field time derivatives, or NULL 3086 - locA - A local vector with auxiliary fields, or NULL 3087 3088 Output Parameters: 3089 + u - The field coefficients 3090 . u_t - The fields derivative coefficients 3091 - a - The auxiliary field coefficients 3092 3093 Level: developer 3094 3095 .seealso: DMPlexGetFaceFields() 3096 @*/ 3097 PetscErrorCode DMPlexGetCellFields(DM dm, IS cellIS, Vec locX, Vec locX_t, Vec locA, PetscScalar **u, PetscScalar **u_t, PetscScalar **a) 3098 { 3099 DM plex, plexA = NULL; 3100 PetscSection section, sectionAux; 3101 PetscDS prob; 3102 const PetscInt *cells; 3103 PetscInt cStart, cEnd, numCells, totDim, totDimAux, c; 3104 PetscErrorCode ierr; 3105 3106 PetscFunctionBegin; 3107 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3108 PetscValidHeaderSpecific(locX, VEC_CLASSID, 4); 3109 if (locX_t) {PetscValidHeaderSpecific(locX_t, VEC_CLASSID, 5);} 3110 if (locA) {PetscValidHeaderSpecific(locA, VEC_CLASSID, 6);} 3111 PetscValidPointer(u, 7); 3112 PetscValidPointer(u_t, 8); 3113 PetscValidPointer(a, 9); 3114 ierr = DMPlexConvertPlex(dm, &plex, PETSC_FALSE);CHKERRQ(ierr); 3115 ierr = ISGetPointRange(cellIS, &cStart, &cEnd, &cells);CHKERRQ(ierr); 3116 ierr = DMGetLocalSection(dm, §ion);CHKERRQ(ierr); 3117 ierr = DMGetCellDS(dm, cStart, &prob);CHKERRQ(ierr); 3118 ierr = PetscDSGetTotalDimension(prob, &totDim);CHKERRQ(ierr); 3119 if (locA) { 3120 DM dmAux; 3121 PetscDS probAux; 3122 3123 ierr = VecGetDM(locA, &dmAux);CHKERRQ(ierr); 3124 ierr = DMPlexConvertPlex(dmAux, &plexA, PETSC_FALSE);CHKERRQ(ierr); 3125 ierr = DMGetLocalSection(dmAux, §ionAux);CHKERRQ(ierr); 3126 ierr = DMGetDS(dmAux, &probAux);CHKERRQ(ierr); 3127 ierr = PetscDSGetTotalDimension(probAux, &totDimAux);CHKERRQ(ierr); 3128 } 3129 numCells = cEnd - cStart; 3130 ierr = DMGetWorkArray(dm, numCells*totDim, MPIU_SCALAR, u);CHKERRQ(ierr); 3131 if (locX_t) {ierr = DMGetWorkArray(dm, numCells*totDim, MPIU_SCALAR, u_t);CHKERRQ(ierr);} else {*u_t = NULL;} 3132 if (locA) {ierr = DMGetWorkArray(dm, numCells*totDimAux, MPIU_SCALAR, a);CHKERRQ(ierr);} else {*a = NULL;} 3133 for (c = cStart; c < cEnd; ++c) { 3134 const PetscInt cell = cells ? cells[c] : c; 3135 const PetscInt cind = c - cStart; 3136 PetscScalar *x = NULL, *x_t = NULL, *ul = *u, *ul_t = *u_t, *al = *a; 3137 PetscInt i; 3138 3139 ierr = DMPlexVecGetClosure(plex, section, locX, cell, NULL, &x);CHKERRQ(ierr); 3140 for (i = 0; i < totDim; ++i) ul[cind*totDim+i] = x[i]; 3141 ierr = DMPlexVecRestoreClosure(plex, section, locX, cell, NULL, &x);CHKERRQ(ierr); 3142 if (locX_t) { 3143 ierr = DMPlexVecGetClosure(plex, section, locX_t, cell, NULL, &x_t);CHKERRQ(ierr); 3144 for (i = 0; i < totDim; ++i) ul_t[cind*totDim+i] = x_t[i]; 3145 ierr = DMPlexVecRestoreClosure(plex, section, locX_t, cell, NULL, &x_t);CHKERRQ(ierr); 3146 } 3147 if (locA) { 3148 PetscInt subcell; 3149 ierr = DMPlexGetAuxiliaryPoint(plex, plexA, cell, &subcell);CHKERRQ(ierr); 3150 ierr = DMPlexVecGetClosure(plexA, sectionAux, locA, subcell, NULL, &x);CHKERRQ(ierr); 3151 for (i = 0; i < totDimAux; ++i) al[cind*totDimAux+i] = x[i]; 3152 ierr = DMPlexVecRestoreClosure(plexA, sectionAux, locA, subcell, NULL, &x);CHKERRQ(ierr); 3153 } 3154 } 3155 ierr = DMDestroy(&plex);CHKERRQ(ierr); 3156 if (locA) {ierr = DMDestroy(&plexA);CHKERRQ(ierr);} 3157 ierr = ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);CHKERRQ(ierr); 3158 PetscFunctionReturn(0); 3159 } 3160 3161 /*@C 3162 DMPlexRestoreCellFields - Restore the field values values for a chunk of cells 3163 3164 Input Parameters: 3165 + dm - The DM 3166 . cellIS - The cells to include 3167 . locX - A local vector with the solution fields 3168 . locX_t - A local vector with solution field time derivatives, or NULL 3169 - locA - A local vector with auxiliary fields, or NULL 3170 3171 Output Parameters: 3172 + u - The field coefficients 3173 . u_t - The fields derivative coefficients 3174 - a - The auxiliary field coefficients 3175 3176 Level: developer 3177 3178 .seealso: DMPlexGetFaceFields() 3179 @*/ 3180 PetscErrorCode DMPlexRestoreCellFields(DM dm, IS cellIS, Vec locX, Vec locX_t, Vec locA, PetscScalar **u, PetscScalar **u_t, PetscScalar **a) 3181 { 3182 PetscErrorCode ierr; 3183 3184 PetscFunctionBegin; 3185 ierr = DMRestoreWorkArray(dm, 0, MPIU_SCALAR, u);CHKERRQ(ierr); 3186 if (locX_t) {ierr = DMRestoreWorkArray(dm, 0, MPIU_SCALAR, u_t);CHKERRQ(ierr);} 3187 if (locA) {ierr = DMRestoreWorkArray(dm, 0, MPIU_SCALAR, a);CHKERRQ(ierr);} 3188 PetscFunctionReturn(0); 3189 } 3190 3191 /*@C 3192 DMPlexGetFaceFields - Retrieve the field values values for a chunk of faces 3193 3194 Input Parameters: 3195 + dm - The DM 3196 . fStart - The first face to include 3197 . fEnd - The first face to exclude 3198 . locX - A local vector with the solution fields 3199 . locX_t - A local vector with solution field time derivatives, or NULL 3200 . faceGeometry - A local vector with face geometry 3201 . cellGeometry - A local vector with cell geometry 3202 - locaGrad - A local vector with field gradients, or NULL 3203 3204 Output Parameters: 3205 + Nface - The number of faces with field values 3206 . uL - The field values at the left side of the face 3207 - uR - The field values at the right side of the face 3208 3209 Level: developer 3210 3211 .seealso: DMPlexGetCellFields() 3212 @*/ 3213 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) 3214 { 3215 DM dmFace, dmCell, dmGrad = NULL; 3216 PetscSection section; 3217 PetscDS prob; 3218 DMLabel ghostLabel; 3219 const PetscScalar *facegeom, *cellgeom, *x, *lgrad; 3220 PetscBool *isFE; 3221 PetscInt dim, Nf, f, Nc, numFaces = fEnd - fStart, iface, face; 3222 PetscErrorCode ierr; 3223 3224 PetscFunctionBegin; 3225 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3226 PetscValidHeaderSpecific(locX, VEC_CLASSID, 4); 3227 if (locX_t) {PetscValidHeaderSpecific(locX_t, VEC_CLASSID, 5);} 3228 PetscValidHeaderSpecific(faceGeometry, VEC_CLASSID, 6); 3229 PetscValidHeaderSpecific(cellGeometry, VEC_CLASSID, 7); 3230 if (locGrad) {PetscValidHeaderSpecific(locGrad, VEC_CLASSID, 8);} 3231 PetscValidPointer(uL, 9); 3232 PetscValidPointer(uR, 10); 3233 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 3234 ierr = DMGetDS(dm, &prob);CHKERRQ(ierr); 3235 ierr = DMGetLocalSection(dm, §ion);CHKERRQ(ierr); 3236 ierr = PetscDSGetNumFields(prob, &Nf);CHKERRQ(ierr); 3237 ierr = PetscDSGetTotalComponents(prob, &Nc);CHKERRQ(ierr); 3238 ierr = PetscMalloc1(Nf, &isFE);CHKERRQ(ierr); 3239 for (f = 0; f < Nf; ++f) { 3240 PetscObject obj; 3241 PetscClassId id; 3242 3243 ierr = PetscDSGetDiscretization(prob, f, &obj);CHKERRQ(ierr); 3244 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 3245 if (id == PETSCFE_CLASSID) {isFE[f] = PETSC_TRUE;} 3246 else if (id == PETSCFV_CLASSID) {isFE[f] = PETSC_FALSE;} 3247 else {isFE[f] = PETSC_FALSE;} 3248 } 3249 ierr = DMGetLabel(dm, "ghost", &ghostLabel);CHKERRQ(ierr); 3250 ierr = VecGetArrayRead(locX, &x);CHKERRQ(ierr); 3251 ierr = VecGetDM(faceGeometry, &dmFace);CHKERRQ(ierr); 3252 ierr = VecGetArrayRead(faceGeometry, &facegeom);CHKERRQ(ierr); 3253 ierr = VecGetDM(cellGeometry, &dmCell);CHKERRQ(ierr); 3254 ierr = VecGetArrayRead(cellGeometry, &cellgeom);CHKERRQ(ierr); 3255 if (locGrad) { 3256 ierr = VecGetDM(locGrad, &dmGrad);CHKERRQ(ierr); 3257 ierr = VecGetArrayRead(locGrad, &lgrad);CHKERRQ(ierr); 3258 } 3259 ierr = DMGetWorkArray(dm, numFaces*Nc, MPIU_SCALAR, uL);CHKERRQ(ierr); 3260 ierr = DMGetWorkArray(dm, numFaces*Nc, MPIU_SCALAR, uR);CHKERRQ(ierr); 3261 /* Right now just eat the extra work for FE (could make a cell loop) */ 3262 for (face = fStart, iface = 0; face < fEnd; ++face) { 3263 const PetscInt *cells; 3264 PetscFVFaceGeom *fg; 3265 PetscFVCellGeom *cgL, *cgR; 3266 PetscScalar *xL, *xR, *gL, *gR; 3267 PetscScalar *uLl = *uL, *uRl = *uR; 3268 PetscInt ghost, nsupp, nchild; 3269 3270 ierr = DMLabelGetValue(ghostLabel, face, &ghost);CHKERRQ(ierr); 3271 ierr = DMPlexGetSupportSize(dm, face, &nsupp);CHKERRQ(ierr); 3272 ierr = DMPlexGetTreeChildren(dm, face, &nchild, NULL);CHKERRQ(ierr); 3273 if (ghost >= 0 || nsupp > 2 || nchild > 0) continue; 3274 ierr = DMPlexPointLocalRead(dmFace, face, facegeom, &fg);CHKERRQ(ierr); 3275 ierr = DMPlexGetSupport(dm, face, &cells);CHKERRQ(ierr); 3276 ierr = DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cgL);CHKERRQ(ierr); 3277 ierr = DMPlexPointLocalRead(dmCell, cells[1], cellgeom, &cgR);CHKERRQ(ierr); 3278 for (f = 0; f < Nf; ++f) { 3279 PetscInt off; 3280 3281 ierr = PetscDSGetComponentOffset(prob, f, &off);CHKERRQ(ierr); 3282 if (isFE[f]) { 3283 const PetscInt *cone; 3284 PetscInt comp, coneSizeL, coneSizeR, faceLocL, faceLocR, ldof, rdof, d; 3285 3286 xL = xR = NULL; 3287 ierr = PetscSectionGetFieldComponents(section, f, &comp);CHKERRQ(ierr); 3288 ierr = DMPlexVecGetClosure(dm, section, locX, cells[0], &ldof, (PetscScalar **) &xL);CHKERRQ(ierr); 3289 ierr = DMPlexVecGetClosure(dm, section, locX, cells[1], &rdof, (PetscScalar **) &xR);CHKERRQ(ierr); 3290 ierr = DMPlexGetCone(dm, cells[0], &cone);CHKERRQ(ierr); 3291 ierr = DMPlexGetConeSize(dm, cells[0], &coneSizeL);CHKERRQ(ierr); 3292 for (faceLocL = 0; faceLocL < coneSizeL; ++faceLocL) if (cone[faceLocL] == face) break; 3293 ierr = DMPlexGetCone(dm, cells[1], &cone);CHKERRQ(ierr); 3294 ierr = DMPlexGetConeSize(dm, cells[1], &coneSizeR);CHKERRQ(ierr); 3295 for (faceLocR = 0; faceLocR < coneSizeR; ++faceLocR) if (cone[faceLocR] == face) break; 3296 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]); 3297 /* Check that FEM field has values in the right cell (sometimes its an FV ghost cell) */ 3298 /* TODO: this is a hack that might not be right for nonconforming */ 3299 if (faceLocL < coneSizeL) { 3300 ierr = PetscFEEvaluateFaceFields_Internal(prob, f, faceLocL, xL, &uLl[iface*Nc+off]);CHKERRQ(ierr); 3301 if (rdof == ldof && faceLocR < coneSizeR) {ierr = PetscFEEvaluateFaceFields_Internal(prob, f, faceLocR, xR, &uRl[iface*Nc+off]);CHKERRQ(ierr);} 3302 else {for(d = 0; d < comp; ++d) uRl[iface*Nc+off+d] = uLl[iface*Nc+off+d];} 3303 } 3304 else { 3305 ierr = PetscFEEvaluateFaceFields_Internal(prob, f, faceLocR, xR, &uRl[iface*Nc+off]);CHKERRQ(ierr); 3306 ierr = PetscSectionGetFieldComponents(section, f, &comp);CHKERRQ(ierr); 3307 for(d = 0; d < comp; ++d) uLl[iface*Nc+off+d] = uRl[iface*Nc+off+d]; 3308 } 3309 ierr = DMPlexVecRestoreClosure(dm, section, locX, cells[0], &ldof, (PetscScalar **) &xL);CHKERRQ(ierr); 3310 ierr = DMPlexVecRestoreClosure(dm, section, locX, cells[1], &rdof, (PetscScalar **) &xR);CHKERRQ(ierr); 3311 } else { 3312 PetscFV fv; 3313 PetscInt numComp, c; 3314 3315 ierr = PetscDSGetDiscretization(prob, f, (PetscObject *) &fv);CHKERRQ(ierr); 3316 ierr = PetscFVGetNumComponents(fv, &numComp);CHKERRQ(ierr); 3317 ierr = DMPlexPointLocalFieldRead(dm, cells[0], f, x, &xL);CHKERRQ(ierr); 3318 ierr = DMPlexPointLocalFieldRead(dm, cells[1], f, x, &xR);CHKERRQ(ierr); 3319 if (dmGrad) { 3320 PetscReal dxL[3], dxR[3]; 3321 3322 ierr = DMPlexPointLocalRead(dmGrad, cells[0], lgrad, &gL);CHKERRQ(ierr); 3323 ierr = DMPlexPointLocalRead(dmGrad, cells[1], lgrad, &gR);CHKERRQ(ierr); 3324 DMPlex_WaxpyD_Internal(dim, -1, cgL->centroid, fg->centroid, dxL); 3325 DMPlex_WaxpyD_Internal(dim, -1, cgR->centroid, fg->centroid, dxR); 3326 for (c = 0; c < numComp; ++c) { 3327 uLl[iface*Nc+off+c] = xL[c] + DMPlex_DotD_Internal(dim, &gL[c*dim], dxL); 3328 uRl[iface*Nc+off+c] = xR[c] + DMPlex_DotD_Internal(dim, &gR[c*dim], dxR); 3329 } 3330 } else { 3331 for (c = 0; c < numComp; ++c) { 3332 uLl[iface*Nc+off+c] = xL[c]; 3333 uRl[iface*Nc+off+c] = xR[c]; 3334 } 3335 } 3336 } 3337 } 3338 ++iface; 3339 } 3340 *Nface = iface; 3341 ierr = VecRestoreArrayRead(locX, &x);CHKERRQ(ierr); 3342 ierr = VecRestoreArrayRead(faceGeometry, &facegeom);CHKERRQ(ierr); 3343 ierr = VecRestoreArrayRead(cellGeometry, &cellgeom);CHKERRQ(ierr); 3344 if (locGrad) { 3345 ierr = VecRestoreArrayRead(locGrad, &lgrad);CHKERRQ(ierr); 3346 } 3347 ierr = PetscFree(isFE);CHKERRQ(ierr); 3348 PetscFunctionReturn(0); 3349 } 3350 3351 /*@C 3352 DMPlexRestoreFaceFields - Restore the field values values for a chunk of faces 3353 3354 Input Parameters: 3355 + dm - The DM 3356 . fStart - The first face to include 3357 . fEnd - The first face to exclude 3358 . locX - A local vector with the solution fields 3359 . locX_t - A local vector with solution field time derivatives, or NULL 3360 . faceGeometry - A local vector with face geometry 3361 . cellGeometry - A local vector with cell geometry 3362 - locaGrad - A local vector with field gradients, or NULL 3363 3364 Output Parameters: 3365 + Nface - The number of faces with field values 3366 . uL - The field values at the left side of the face 3367 - uR - The field values at the right side of the face 3368 3369 Level: developer 3370 3371 .seealso: DMPlexGetFaceFields() 3372 @*/ 3373 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) 3374 { 3375 PetscErrorCode ierr; 3376 3377 PetscFunctionBegin; 3378 ierr = DMRestoreWorkArray(dm, 0, MPIU_SCALAR, uL);CHKERRQ(ierr); 3379 ierr = DMRestoreWorkArray(dm, 0, MPIU_SCALAR, uR);CHKERRQ(ierr); 3380 PetscFunctionReturn(0); 3381 } 3382 3383 /*@C 3384 DMPlexGetFaceGeometry - Retrieve the geometric values for a chunk of faces 3385 3386 Input Parameters: 3387 + dm - The DM 3388 . fStart - The first face to include 3389 . fEnd - The first face to exclude 3390 . faceGeometry - A local vector with face geometry 3391 - cellGeometry - A local vector with cell geometry 3392 3393 Output Parameters: 3394 + Nface - The number of faces with field values 3395 . fgeom - The extract the face centroid and normal 3396 - vol - The cell volume 3397 3398 Level: developer 3399 3400 .seealso: DMPlexGetCellFields() 3401 @*/ 3402 PetscErrorCode DMPlexGetFaceGeometry(DM dm, PetscInt fStart, PetscInt fEnd, Vec faceGeometry, Vec cellGeometry, PetscInt *Nface, PetscFVFaceGeom **fgeom, PetscReal **vol) 3403 { 3404 DM dmFace, dmCell; 3405 DMLabel ghostLabel; 3406 const PetscScalar *facegeom, *cellgeom; 3407 PetscInt dim, numFaces = fEnd - fStart, iface, face; 3408 PetscErrorCode ierr; 3409 3410 PetscFunctionBegin; 3411 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 3412 PetscValidHeaderSpecific(faceGeometry, VEC_CLASSID, 4); 3413 PetscValidHeaderSpecific(cellGeometry, VEC_CLASSID, 5); 3414 PetscValidPointer(fgeom, 6); 3415 PetscValidPointer(vol, 7); 3416 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 3417 ierr = DMGetLabel(dm, "ghost", &ghostLabel);CHKERRQ(ierr); 3418 ierr = VecGetDM(faceGeometry, &dmFace);CHKERRQ(ierr); 3419 ierr = VecGetArrayRead(faceGeometry, &facegeom);CHKERRQ(ierr); 3420 ierr = VecGetDM(cellGeometry, &dmCell);CHKERRQ(ierr); 3421 ierr = VecGetArrayRead(cellGeometry, &cellgeom);CHKERRQ(ierr); 3422 ierr = PetscMalloc1(numFaces, fgeom);CHKERRQ(ierr); 3423 ierr = DMGetWorkArray(dm, numFaces*2, MPIU_SCALAR, vol);CHKERRQ(ierr); 3424 for (face = fStart, iface = 0; face < fEnd; ++face) { 3425 const PetscInt *cells; 3426 PetscFVFaceGeom *fg; 3427 PetscFVCellGeom *cgL, *cgR; 3428 PetscFVFaceGeom *fgeoml = *fgeom; 3429 PetscReal *voll = *vol; 3430 PetscInt ghost, d, nchild, nsupp; 3431 3432 ierr = DMLabelGetValue(ghostLabel, face, &ghost);CHKERRQ(ierr); 3433 ierr = DMPlexGetSupportSize(dm, face, &nsupp);CHKERRQ(ierr); 3434 ierr = DMPlexGetTreeChildren(dm, face, &nchild, NULL);CHKERRQ(ierr); 3435 if (ghost >= 0 || nsupp > 2 || nchild > 0) continue; 3436 ierr = DMPlexPointLocalRead(dmFace, face, facegeom, &fg);CHKERRQ(ierr); 3437 ierr = DMPlexGetSupport(dm, face, &cells);CHKERRQ(ierr); 3438 ierr = DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cgL);CHKERRQ(ierr); 3439 ierr = DMPlexPointLocalRead(dmCell, cells[1], cellgeom, &cgR);CHKERRQ(ierr); 3440 for (d = 0; d < dim; ++d) { 3441 fgeoml[iface].centroid[d] = fg->centroid[d]; 3442 fgeoml[iface].normal[d] = fg->normal[d]; 3443 } 3444 voll[iface*2+0] = cgL->volume; 3445 voll[iface*2+1] = cgR->volume; 3446 ++iface; 3447 } 3448 *Nface = iface; 3449 ierr = VecRestoreArrayRead(faceGeometry, &facegeom);CHKERRQ(ierr); 3450 ierr = VecRestoreArrayRead(cellGeometry, &cellgeom);CHKERRQ(ierr); 3451 PetscFunctionReturn(0); 3452 } 3453 3454 /*@C 3455 DMPlexRestoreFaceGeometry - Restore the field values values for a chunk of faces 3456 3457 Input Parameters: 3458 + dm - The DM 3459 . fStart - The first face to include 3460 . fEnd - The first face to exclude 3461 . faceGeometry - A local vector with face geometry 3462 - cellGeometry - A local vector with cell geometry 3463 3464 Output Parameters: 3465 + Nface - The number of faces with field values 3466 . fgeom - The extract the face centroid and normal 3467 - vol - The cell volume 3468 3469 Level: developer 3470 3471 .seealso: DMPlexGetFaceFields() 3472 @*/ 3473 PetscErrorCode DMPlexRestoreFaceGeometry(DM dm, PetscInt fStart, PetscInt fEnd, Vec faceGeometry, Vec cellGeometry, PetscInt *Nface, PetscFVFaceGeom **fgeom, PetscReal **vol) 3474 { 3475 PetscErrorCode ierr; 3476 3477 PetscFunctionBegin; 3478 ierr = PetscFree(*fgeom);CHKERRQ(ierr); 3479 ierr = DMRestoreWorkArray(dm, 0, MPIU_REAL, vol);CHKERRQ(ierr); 3480 PetscFunctionReturn(0); 3481 } 3482 3483 PetscErrorCode DMSNESGetFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom) 3484 { 3485 char composeStr[33] = {0}; 3486 PetscObjectId id; 3487 PetscContainer container; 3488 PetscErrorCode ierr; 3489 3490 PetscFunctionBegin; 3491 ierr = PetscObjectGetId((PetscObject)quad,&id);CHKERRQ(ierr); 3492 ierr = PetscSNPrintf(composeStr, 32, "DMSNESGetFEGeom_%x\n", id);CHKERRQ(ierr); 3493 ierr = PetscObjectQuery((PetscObject) pointIS, composeStr, (PetscObject *) &container);CHKERRQ(ierr); 3494 if (container) { 3495 ierr = PetscContainerGetPointer(container, (void **) geom);CHKERRQ(ierr); 3496 } else { 3497 ierr = DMFieldCreateFEGeom(coordField, pointIS, quad, faceData, geom);CHKERRQ(ierr); 3498 ierr = PetscContainerCreate(PETSC_COMM_SELF,&container);CHKERRQ(ierr); 3499 ierr = PetscContainerSetPointer(container, (void *) *geom);CHKERRQ(ierr); 3500 ierr = PetscContainerSetUserDestroy(container, PetscContainerUserDestroy_PetscFEGeom);CHKERRQ(ierr); 3501 ierr = PetscObjectCompose((PetscObject) pointIS, composeStr, (PetscObject) container);CHKERRQ(ierr); 3502 ierr = PetscContainerDestroy(&container);CHKERRQ(ierr); 3503 } 3504 PetscFunctionReturn(0); 3505 } 3506 3507 PetscErrorCode DMSNESRestoreFEGeom(DMField coordField, IS pointIS, PetscQuadrature quad, PetscBool faceData, PetscFEGeom **geom) 3508 { 3509 PetscFunctionBegin; 3510 *geom = NULL; 3511 PetscFunctionReturn(0); 3512 } 3513 3514 PetscErrorCode DMPlexComputeResidual_Patch_Internal(DM dm, PetscSection section, IS cellIS, PetscReal t, Vec locX, Vec locX_t, Vec locF, void *user) 3515 { 3516 DM_Plex *mesh = (DM_Plex *) dm->data; 3517 const char *name = "Residual"; 3518 DM dmAux = NULL; 3519 DMLabel ghostLabel = NULL; 3520 PetscDS prob = NULL; 3521 PetscDS probAux = NULL; 3522 PetscBool useFEM = PETSC_FALSE; 3523 PetscBool isImplicit = (locX_t || t == PETSC_MIN_REAL) ? PETSC_TRUE : PETSC_FALSE; 3524 DMField coordField = NULL; 3525 Vec locA; 3526 PetscScalar *u = NULL, *u_t, *a, *uL = NULL, *uR = NULL; 3527 IS chunkIS; 3528 const PetscInt *cells; 3529 PetscInt cStart, cEnd, numCells; 3530 PetscInt Nf, f, totDim, totDimAux, numChunks, cellChunkSize, chunk, fStart, fEnd; 3531 PetscInt maxDegree = PETSC_MAX_INT; 3532 PetscQuadrature affineQuad = NULL, *quads = NULL; 3533 PetscFEGeom *affineGeom = NULL, **geoms = NULL; 3534 PetscErrorCode ierr; 3535 3536 PetscFunctionBegin; 3537 ierr = PetscLogEventBegin(DMPLEX_ResidualFEM,dm,0,0,0);CHKERRQ(ierr); 3538 /* FEM+FVM */ 3539 /* 1: Get sizes from dm and dmAux */ 3540 ierr = DMGetLabel(dm, "ghost", &ghostLabel);CHKERRQ(ierr); 3541 ierr = DMGetDS(dm, &prob);CHKERRQ(ierr); 3542 ierr = PetscDSGetNumFields(prob, &Nf);CHKERRQ(ierr); 3543 ierr = PetscDSGetTotalDimension(prob, &totDim);CHKERRQ(ierr); 3544 ierr = PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &locA);CHKERRQ(ierr); 3545 if (locA) { 3546 ierr = VecGetDM(locA, &dmAux);CHKERRQ(ierr); 3547 ierr = DMGetDS(dmAux, &probAux);CHKERRQ(ierr); 3548 ierr = PetscDSGetTotalDimension(probAux, &totDimAux);CHKERRQ(ierr); 3549 } 3550 /* 2: Get geometric data */ 3551 for (f = 0; f < Nf; ++f) { 3552 PetscObject obj; 3553 PetscClassId id; 3554 PetscBool fimp; 3555 3556 ierr = PetscDSGetImplicit(prob, f, &fimp);CHKERRQ(ierr); 3557 if (isImplicit != fimp) continue; 3558 ierr = PetscDSGetDiscretization(prob, f, &obj);CHKERRQ(ierr); 3559 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 3560 if (id == PETSCFE_CLASSID) {useFEM = PETSC_TRUE;} 3561 if (id == PETSCFV_CLASSID) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Use of FVM with PCPATCH not yet implemented"); 3562 } 3563 if (useFEM) { 3564 ierr = DMGetCoordinateField(dm, &coordField);CHKERRQ(ierr); 3565 ierr = DMFieldGetDegree(coordField,cellIS,NULL,&maxDegree);CHKERRQ(ierr); 3566 if (maxDegree <= 1) { 3567 ierr = DMFieldCreateDefaultQuadrature(coordField,cellIS,&affineQuad);CHKERRQ(ierr); 3568 if (affineQuad) { 3569 ierr = DMSNESGetFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom);CHKERRQ(ierr); 3570 } 3571 } else { 3572 ierr = PetscCalloc2(Nf,&quads,Nf,&geoms);CHKERRQ(ierr); 3573 for (f = 0; f < Nf; ++f) { 3574 PetscObject obj; 3575 PetscClassId id; 3576 PetscBool fimp; 3577 3578 ierr = PetscDSGetImplicit(prob, f, &fimp);CHKERRQ(ierr); 3579 if (isImplicit != fimp) continue; 3580 ierr = PetscDSGetDiscretization(prob, f, &obj);CHKERRQ(ierr); 3581 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 3582 if (id == PETSCFE_CLASSID) { 3583 PetscFE fe = (PetscFE) obj; 3584 3585 ierr = PetscFEGetQuadrature(fe, &quads[f]);CHKERRQ(ierr); 3586 ierr = PetscObjectReference((PetscObject)quads[f]);CHKERRQ(ierr); 3587 ierr = DMSNESGetFEGeom(coordField,cellIS,quads[f],PETSC_FALSE,&geoms[f]);CHKERRQ(ierr); 3588 } 3589 } 3590 } 3591 } 3592 /* Loop over chunks */ 3593 ierr = ISGetPointRange(cellIS, &cStart, &cEnd, &cells);CHKERRQ(ierr); 3594 ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr); 3595 if (useFEM) {ierr = ISCreate(PETSC_COMM_SELF, &chunkIS);CHKERRQ(ierr);} 3596 numCells = cEnd - cStart; 3597 numChunks = 1; 3598 cellChunkSize = numCells/numChunks; 3599 numChunks = PetscMin(1,numCells); 3600 for (chunk = 0; chunk < numChunks; ++chunk) { 3601 PetscScalar *elemVec, *fluxL = NULL, *fluxR = NULL; 3602 PetscReal *vol = NULL; 3603 PetscFVFaceGeom *fgeom = NULL; 3604 PetscInt cS = cStart+chunk*cellChunkSize, cE = PetscMin(cS+cellChunkSize, cEnd), numCells = cE - cS, c; 3605 PetscInt numFaces = 0; 3606 3607 /* Extract field coefficients */ 3608 if (useFEM) { 3609 ierr = ISGetPointSubrange(chunkIS, cS, cE, cells);CHKERRQ(ierr); 3610 ierr = DMPlexGetCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a);CHKERRQ(ierr); 3611 ierr = DMGetWorkArray(dm, numCells*totDim, MPIU_SCALAR, &elemVec);CHKERRQ(ierr); 3612 ierr = PetscArrayzero(elemVec, numCells*totDim);CHKERRQ(ierr); 3613 } 3614 /* TODO We will interlace both our field coefficients (u, u_t, uL, uR, etc.) and our output (elemVec, fL, fR). I think this works */ 3615 /* Loop over fields */ 3616 for (f = 0; f < Nf; ++f) { 3617 PetscObject obj; 3618 PetscClassId id; 3619 PetscBool fimp; 3620 PetscInt numChunks, numBatches, batchSize, numBlocks, blockSize, Ne, Nr, offset; 3621 3622 ierr = PetscDSGetImplicit(prob, f, &fimp);CHKERRQ(ierr); 3623 if (isImplicit != fimp) continue; 3624 ierr = PetscDSGetDiscretization(prob, f, &obj);CHKERRQ(ierr); 3625 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 3626 if (id == PETSCFE_CLASSID) { 3627 PetscFE fe = (PetscFE) obj; 3628 PetscFEGeom *geom = affineGeom ? affineGeom : geoms[f]; 3629 PetscFEGeom *chunkGeom = NULL; 3630 PetscQuadrature quad = affineQuad ? affineQuad : quads[f]; 3631 PetscInt Nq, Nb; 3632 3633 ierr = PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);CHKERRQ(ierr); 3634 ierr = PetscQuadratureGetData(quad, NULL, NULL, &Nq, NULL, NULL);CHKERRQ(ierr); 3635 ierr = PetscFEGetDimension(fe, &Nb);CHKERRQ(ierr); 3636 blockSize = Nb; 3637 batchSize = numBlocks * blockSize; 3638 ierr = PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);CHKERRQ(ierr); 3639 numChunks = numCells / (numBatches*batchSize); 3640 Ne = numChunks*numBatches*batchSize; 3641 Nr = numCells % (numBatches*batchSize); 3642 offset = numCells - Nr; 3643 /* Integrate FE residual to get elemVec (need fields at quadrature points) */ 3644 /* 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) */ 3645 ierr = PetscFEGeomGetChunk(geom,0,offset,&chunkGeom);CHKERRQ(ierr); 3646 ierr = PetscFEIntegrateResidual(prob, f, Ne, chunkGeom, u, u_t, probAux, a, t, elemVec);CHKERRQ(ierr); 3647 ierr = PetscFEGeomGetChunk(geom,offset,numCells,&chunkGeom);CHKERRQ(ierr); 3648 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); 3649 ierr = PetscFEGeomRestoreChunk(geom,offset,numCells,&chunkGeom);CHKERRQ(ierr); 3650 } else if (id == PETSCFV_CLASSID) { 3651 PetscFV fv = (PetscFV) obj; 3652 3653 Ne = numFaces; 3654 /* Riemann solve over faces (need fields at face centroids) */ 3655 /* We need to evaluate FE fields at those coordinates */ 3656 ierr = PetscFVIntegrateRHSFunction(fv, prob, f, Ne, fgeom, vol, uL, uR, fluxL, fluxR);CHKERRQ(ierr); 3657 } else SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %D", f); 3658 } 3659 /* Loop over domain */ 3660 if (useFEM) { 3661 /* Add elemVec to locX */ 3662 for (c = cS; c < cE; ++c) { 3663 const PetscInt cell = cells ? cells[c] : c; 3664 const PetscInt cind = c - cStart; 3665 3666 if (mesh->printFEM > 1) {ierr = DMPrintCellVector(cell, name, totDim, &elemVec[cind*totDim]);CHKERRQ(ierr);} 3667 if (ghostLabel) { 3668 PetscInt ghostVal; 3669 3670 ierr = DMLabelGetValue(ghostLabel,cell,&ghostVal);CHKERRQ(ierr); 3671 if (ghostVal > 0) continue; 3672 } 3673 ierr = DMPlexVecSetClosure(dm, section, locF, cell, &elemVec[cind*totDim], ADD_ALL_VALUES);CHKERRQ(ierr); 3674 } 3675 } 3676 /* Handle time derivative */ 3677 if (locX_t) { 3678 PetscScalar *x_t, *fa; 3679 3680 ierr = VecGetArray(locF, &fa);CHKERRQ(ierr); 3681 ierr = VecGetArray(locX_t, &x_t);CHKERRQ(ierr); 3682 for (f = 0; f < Nf; ++f) { 3683 PetscFV fv; 3684 PetscObject obj; 3685 PetscClassId id; 3686 PetscInt pdim, d; 3687 3688 ierr = PetscDSGetDiscretization(prob, f, &obj);CHKERRQ(ierr); 3689 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 3690 if (id != PETSCFV_CLASSID) continue; 3691 fv = (PetscFV) obj; 3692 ierr = PetscFVGetNumComponents(fv, &pdim);CHKERRQ(ierr); 3693 for (c = cS; c < cE; ++c) { 3694 const PetscInt cell = cells ? cells[c] : c; 3695 PetscScalar *u_t, *r; 3696 3697 if (ghostLabel) { 3698 PetscInt ghostVal; 3699 3700 ierr = DMLabelGetValue(ghostLabel, cell, &ghostVal);CHKERRQ(ierr); 3701 if (ghostVal > 0) continue; 3702 } 3703 ierr = DMPlexPointLocalFieldRead(dm, cell, f, x_t, &u_t);CHKERRQ(ierr); 3704 ierr = DMPlexPointLocalFieldRef(dm, cell, f, fa, &r);CHKERRQ(ierr); 3705 for (d = 0; d < pdim; ++d) r[d] += u_t[d]; 3706 } 3707 } 3708 ierr = VecRestoreArray(locX_t, &x_t);CHKERRQ(ierr); 3709 ierr = VecRestoreArray(locF, &fa);CHKERRQ(ierr); 3710 } 3711 if (useFEM) { 3712 ierr = DMPlexRestoreCellFields(dm, chunkIS, locX, locX_t, locA, &u, &u_t, &a);CHKERRQ(ierr); 3713 ierr = DMRestoreWorkArray(dm, numCells*totDim, MPIU_SCALAR, &elemVec);CHKERRQ(ierr); 3714 } 3715 } 3716 if (useFEM) {ierr = ISDestroy(&chunkIS);CHKERRQ(ierr);} 3717 ierr = ISRestorePointRange(cellIS, &cStart, &cEnd, &cells);CHKERRQ(ierr); 3718 /* TODO Could include boundary residual here (see DMPlexComputeResidual_Internal) */ 3719 if (useFEM) { 3720 if (maxDegree <= 1) { 3721 ierr = DMSNESRestoreFEGeom(coordField,cellIS,affineQuad,PETSC_FALSE,&affineGeom);CHKERRQ(ierr); 3722 ierr = PetscQuadratureDestroy(&affineQuad);CHKERRQ(ierr); 3723 } else { 3724 for (f = 0; f < Nf; ++f) { 3725 ierr = DMSNESRestoreFEGeom(coordField,cellIS,quads[f],PETSC_FALSE,&geoms[f]);CHKERRQ(ierr); 3726 ierr = PetscQuadratureDestroy(&quads[f]);CHKERRQ(ierr); 3727 } 3728 ierr = PetscFree2(quads,geoms);CHKERRQ(ierr); 3729 } 3730 } 3731 ierr = PetscLogEventEnd(DMPLEX_ResidualFEM,dm,0,0,0);CHKERRQ(ierr); 3732 PetscFunctionReturn(0); 3733 } 3734 3735 /* 3736 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 3737 3738 X - The local solution vector 3739 X_t - The local solution time derviative vector, or NULL 3740 */ 3741 PetscErrorCode DMPlexComputeJacobian_Patch_Internal(DM dm, PetscSection section, PetscSection globalSection, IS cellIS, 3742 PetscReal t, PetscReal X_tShift, Vec X, Vec X_t, Mat Jac, Mat JacP, void *ctx) 3743 { 3744 DM_Plex *mesh = (DM_Plex *) dm->data; 3745 const char *name = "Jacobian", *nameP = "JacobianPre"; 3746 DM dmAux = NULL; 3747 PetscDS prob, probAux = NULL; 3748 PetscSection sectionAux = NULL; 3749 Vec A; 3750 DMField coordField; 3751 PetscFEGeom *cgeomFEM; 3752 PetscQuadrature qGeom = NULL; 3753 Mat J = Jac, JP = JacP; 3754 PetscScalar *work, *u = NULL, *u_t = NULL, *a = NULL, *elemMat = NULL, *elemMatP = NULL, *elemMatD = NULL; 3755 PetscBool hasJac, hasPrec, hasDyn, assembleJac, isMatIS, isMatISP, *isFE, hasFV = PETSC_FALSE; 3756 const PetscInt *cells; 3757 PetscInt Nf, fieldI, fieldJ, maxDegree, numCells, cStart, cEnd, numChunks, chunkSize, chunk, totDim, totDimAux = 0, sz, wsz, off = 0, offCell = 0; 3758 PetscErrorCode ierr; 3759 3760 PetscFunctionBegin; 3761 CHKMEMQ; 3762 ierr = ISGetLocalSize(cellIS, &numCells);CHKERRQ(ierr); 3763 ierr = ISGetPointRange(cellIS, &cStart, &cEnd, &cells);CHKERRQ(ierr); 3764 ierr = PetscLogEventBegin(DMPLEX_JacobianFEM,dm,0,0,0);CHKERRQ(ierr); 3765 ierr = DMGetDS(dm, &prob);CHKERRQ(ierr); 3766 ierr = PetscObjectQuery((PetscObject) dm, "dmAux", (PetscObject *) &dmAux);CHKERRQ(ierr); 3767 ierr = PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &A);CHKERRQ(ierr); 3768 if (dmAux) { 3769 ierr = DMGetLocalSection(dmAux, §ionAux);CHKERRQ(ierr); 3770 ierr = DMGetDS(dmAux, &probAux);CHKERRQ(ierr); 3771 } 3772 /* Get flags */ 3773 ierr = PetscDSGetNumFields(prob, &Nf);CHKERRQ(ierr); 3774 ierr = DMGetWorkArray(dm, Nf, MPIU_BOOL, &isFE);CHKERRQ(ierr); 3775 for (fieldI = 0; fieldI < Nf; ++fieldI) { 3776 PetscObject disc; 3777 PetscClassId id; 3778 ierr = PetscDSGetDiscretization(prob, fieldI, &disc);CHKERRQ(ierr); 3779 ierr = PetscObjectGetClassId(disc, &id);CHKERRQ(ierr); 3780 if (id == PETSCFE_CLASSID) {isFE[fieldI] = PETSC_TRUE;} 3781 else if (id == PETSCFV_CLASSID) {hasFV = PETSC_TRUE; isFE[fieldI] = PETSC_FALSE;} 3782 } 3783 ierr = PetscDSHasJacobian(prob, &hasJac);CHKERRQ(ierr); 3784 ierr = PetscDSHasJacobianPreconditioner(prob, &hasPrec);CHKERRQ(ierr); 3785 ierr = PetscDSHasDynamicJacobian(prob, &hasDyn);CHKERRQ(ierr); 3786 assembleJac = hasJac && hasPrec && (Jac != JacP) ? PETSC_TRUE : PETSC_FALSE; 3787 hasDyn = hasDyn && (X_tShift != 0.0) ? PETSC_TRUE : PETSC_FALSE; 3788 ierr = PetscObjectTypeCompare((PetscObject) Jac, MATIS, &isMatIS);CHKERRQ(ierr); 3789 ierr = PetscObjectTypeCompare((PetscObject) JacP, MATIS, &isMatISP);CHKERRQ(ierr); 3790 /* Setup input data and temp arrays (should be DMGetWorkArray) */ 3791 if (isMatISP || isMatISP) {ierr = DMPlexGetSubdomainSection(dm, &globalSection);CHKERRQ(ierr);} 3792 if (isMatIS) {ierr = MatISGetLocalMat(Jac, &J);CHKERRQ(ierr);} 3793 if (isMatISP) {ierr = MatISGetLocalMat(JacP, &JP);CHKERRQ(ierr);} 3794 if (hasFV) {ierr = MatSetOption(JP, MAT_IGNORE_ZERO_ENTRIES, PETSC_TRUE);CHKERRQ(ierr);} /* No allocated space for FV stuff, so ignore the zero entries */ 3795 ierr = PetscObjectQuery((PetscObject) dm, "dmAux", (PetscObject *) &dmAux);CHKERRQ(ierr); 3796 ierr = PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &A);CHKERRQ(ierr); 3797 ierr = PetscDSGetTotalDimension(prob, &totDim);CHKERRQ(ierr); 3798 if (probAux) {ierr = PetscDSGetTotalDimension(probAux, &totDimAux);CHKERRQ(ierr);} 3799 CHKMEMQ; 3800 /* Compute batch sizes */ 3801 if (isFE[0]) { 3802 PetscFE fe; 3803 PetscQuadrature q; 3804 PetscInt numQuadPoints, numBatches, batchSize, numBlocks, blockSize, Nb; 3805 3806 ierr = PetscDSGetDiscretization(prob, 0, (PetscObject *) &fe);CHKERRQ(ierr); 3807 ierr = PetscFEGetQuadrature(fe, &q);CHKERRQ(ierr); 3808 ierr = PetscQuadratureGetData(q, NULL, NULL, &numQuadPoints, NULL, NULL);CHKERRQ(ierr); 3809 ierr = PetscFEGetDimension(fe, &Nb);CHKERRQ(ierr); 3810 ierr = PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);CHKERRQ(ierr); 3811 blockSize = Nb*numQuadPoints; 3812 batchSize = numBlocks * blockSize; 3813 chunkSize = numBatches * batchSize; 3814 numChunks = numCells / chunkSize + numCells % chunkSize; 3815 ierr = PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);CHKERRQ(ierr); 3816 } else { 3817 chunkSize = numCells; 3818 numChunks = 1; 3819 } 3820 /* Get work space */ 3821 wsz = (((X?1:0) + (X_t?1:0) + (dmAux?1:0))*totDim + ((hasJac?1:0) + (hasPrec?1:0) + (hasDyn?1:0))*totDim*totDim)*chunkSize; 3822 ierr = DMGetWorkArray(dm, wsz, MPIU_SCALAR, &work);CHKERRQ(ierr); 3823 ierr = PetscArrayzero(work, wsz);CHKERRQ(ierr); 3824 off = 0; 3825 u = X ? (sz = chunkSize*totDim, off += sz, work+off-sz) : NULL; 3826 u_t = X_t ? (sz = chunkSize*totDim, off += sz, work+off-sz) : NULL; 3827 a = dmAux ? (sz = chunkSize*totDimAux, off += sz, work+off-sz) : NULL; 3828 elemMat = hasJac ? (sz = chunkSize*totDim*totDim, off += sz, work+off-sz) : NULL; 3829 elemMatP = hasPrec ? (sz = chunkSize*totDim*totDim, off += sz, work+off-sz) : NULL; 3830 elemMatD = hasDyn ? (sz = chunkSize*totDim*totDim, off += sz, work+off-sz) : NULL; 3831 if (off != wsz) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Error is workspace size %D should be %D", off, wsz); 3832 /* Setup geometry */ 3833 ierr = DMGetCoordinateField(dm, &coordField);CHKERRQ(ierr); 3834 ierr = DMFieldGetDegree(coordField, cellIS, NULL, &maxDegree);CHKERRQ(ierr); 3835 if (maxDegree <= 1) {ierr = DMFieldCreateDefaultQuadrature(coordField, cellIS, &qGeom);CHKERRQ(ierr);} 3836 if (!qGeom) { 3837 PetscFE fe; 3838 3839 ierr = PetscDSGetDiscretization(prob, 0, (PetscObject *) &fe);CHKERRQ(ierr); 3840 ierr = PetscFEGetQuadrature(fe, &qGeom);CHKERRQ(ierr); 3841 ierr = PetscObjectReference((PetscObject) qGeom);CHKERRQ(ierr); 3842 } 3843 ierr = DMSNESGetFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM);CHKERRQ(ierr); 3844 /* Compute volume integrals */ 3845 if (assembleJac) {ierr = MatZeroEntries(J);CHKERRQ(ierr);} 3846 ierr = MatZeroEntries(JP);CHKERRQ(ierr); 3847 for (chunk = 0; chunk < numChunks; ++chunk, offCell += chunkSize) { 3848 const PetscInt Ncell = PetscMin(chunkSize, numCells - offCell); 3849 PetscInt c; 3850 3851 /* Extract values */ 3852 for (c = 0; c < Ncell; ++c) { 3853 const PetscInt cell = cells ? cells[c+offCell] : c+offCell; 3854 PetscScalar *x = NULL, *x_t = NULL; 3855 PetscInt i; 3856 3857 if (X) { 3858 ierr = DMPlexVecGetClosure(dm, section, X, cell, NULL, &x);CHKERRQ(ierr); 3859 for (i = 0; i < totDim; ++i) u[c*totDim+i] = x[i]; 3860 ierr = DMPlexVecRestoreClosure(dm, section, X, cell, NULL, &x);CHKERRQ(ierr); 3861 } 3862 if (X_t) { 3863 ierr = DMPlexVecGetClosure(dm, section, X_t, cell, NULL, &x_t);CHKERRQ(ierr); 3864 for (i = 0; i < totDim; ++i) u_t[c*totDim+i] = x_t[i]; 3865 ierr = DMPlexVecRestoreClosure(dm, section, X_t, cell, NULL, &x_t);CHKERRQ(ierr); 3866 } 3867 if (dmAux) { 3868 ierr = DMPlexVecGetClosure(dmAux, sectionAux, A, cell, NULL, &x);CHKERRQ(ierr); 3869 for (i = 0; i < totDimAux; ++i) a[c*totDimAux+i] = x[i]; 3870 ierr = DMPlexVecRestoreClosure(dmAux, sectionAux, A, cell, NULL, &x);CHKERRQ(ierr); 3871 } 3872 } 3873 CHKMEMQ; 3874 for (fieldI = 0; fieldI < Nf; ++fieldI) { 3875 PetscFE fe; 3876 ierr = PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fe);CHKERRQ(ierr); 3877 for (fieldJ = 0; fieldJ < Nf; ++fieldJ) { 3878 if (hasJac) {ierr = PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN, fieldI, fieldJ, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMat);CHKERRQ(ierr);} 3879 if (hasPrec) {ierr = PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_PRE, fieldI, fieldJ, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMatP);CHKERRQ(ierr);} 3880 if (hasDyn) {ierr = PetscFEIntegrateJacobian(prob, PETSCFE_JACOBIAN_DYN, fieldI, fieldJ, Ncell, cgeomFEM, u, u_t, probAux, a, t, X_tShift, elemMatD);CHKERRQ(ierr);} 3881 } 3882 /* For finite volume, add the identity */ 3883 if (!isFE[fieldI]) { 3884 PetscFV fv; 3885 PetscInt eOffset = 0, Nc, fc, foff; 3886 3887 ierr = PetscDSGetFieldOffset(prob, fieldI, &foff);CHKERRQ(ierr); 3888 ierr = PetscDSGetDiscretization(prob, fieldI, (PetscObject *) &fv);CHKERRQ(ierr); 3889 ierr = PetscFVGetNumComponents(fv, &Nc);CHKERRQ(ierr); 3890 for (c = 0; c < chunkSize; ++c, eOffset += totDim*totDim) { 3891 for (fc = 0; fc < Nc; ++fc) { 3892 const PetscInt i = foff + fc; 3893 if (hasJac) {elemMat [eOffset+i*totDim+i] = 1.0;} 3894 if (hasPrec) {elemMatP[eOffset+i*totDim+i] = 1.0;} 3895 } 3896 } 3897 } 3898 } 3899 CHKMEMQ; 3900 /* Add contribution from X_t */ 3901 if (hasDyn) {for (c = 0; c < chunkSize*totDim*totDim; ++c) elemMat[c] += X_tShift*elemMatD[c];} 3902 /* Insert values into matrix */ 3903 for (c = 0; c < Ncell; ++c) { 3904 const PetscInt cell = cells ? cells[c+offCell] : c+offCell; 3905 if (mesh->printFEM > 1) { 3906 if (hasJac) {ierr = DMPrintCellMatrix(cell, name, totDim, totDim, &elemMat[(c-cStart)*totDim*totDim]);CHKERRQ(ierr);} 3907 if (hasPrec) {ierr = DMPrintCellMatrix(cell, nameP, totDim, totDim, &elemMatP[(c-cStart)*totDim*totDim]);CHKERRQ(ierr);} 3908 } 3909 if (assembleJac) {ierr = DMPlexMatSetClosure(dm, section, globalSection, Jac, cell, &elemMat[(c-cStart)*totDim*totDim], ADD_VALUES);CHKERRQ(ierr);} 3910 ierr = DMPlexMatSetClosure(dm, section, globalSection, JP, cell, &elemMat[(c-cStart)*totDim*totDim], ADD_VALUES);CHKERRQ(ierr); 3911 } 3912 CHKMEMQ; 3913 } 3914 /* Cleanup */ 3915 ierr = DMSNESRestoreFEGeom(coordField, cellIS, qGeom, PETSC_FALSE, &cgeomFEM);CHKERRQ(ierr); 3916 ierr = PetscQuadratureDestroy(&qGeom);CHKERRQ(ierr); 3917 if (hasFV) {ierr = MatSetOption(JacP, MAT_IGNORE_ZERO_ENTRIES, PETSC_FALSE);CHKERRQ(ierr);} 3918 ierr = DMRestoreWorkArray(dm, Nf, MPIU_BOOL, &isFE);CHKERRQ(ierr); 3919 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); 3920 /* Compute boundary integrals */ 3921 /* ierr = DMPlexComputeBdJacobian_Internal(dm, X, X_t, t, X_tShift, Jac, JacP, ctx);CHKERRQ(ierr); */ 3922 /* Assemble matrix */ 3923 if (assembleJac) {ierr = MatAssemblyBegin(Jac, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);ierr = MatAssemblyEnd(Jac, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);} 3924 ierr = MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);ierr = MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 3925 ierr = PetscLogEventEnd(DMPLEX_JacobianFEM,dm,0,0,0);CHKERRQ(ierr); 3926 CHKMEMQ; 3927 PetscFunctionReturn(0); 3928 } 3929