1 #include <petsc-private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 3 #include <petsc-private/petscfeimpl.h> 4 #include <petsc-private/petscfvimpl.h> 5 6 #undef __FUNCT__ 7 #define __FUNCT__ "DMPlexGetScale" 8 PetscErrorCode DMPlexGetScale(DM dm, PetscUnit unit, PetscReal *scale) 9 { 10 DM_Plex *mesh = (DM_Plex*) dm->data; 11 12 PetscFunctionBegin; 13 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 14 PetscValidPointer(scale, 3); 15 *scale = mesh->scale[unit]; 16 PetscFunctionReturn(0); 17 } 18 19 #undef __FUNCT__ 20 #define __FUNCT__ "DMPlexSetScale" 21 PetscErrorCode DMPlexSetScale(DM dm, PetscUnit unit, PetscReal scale) 22 { 23 DM_Plex *mesh = (DM_Plex*) dm->data; 24 25 PetscFunctionBegin; 26 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 27 mesh->scale[unit] = scale; 28 PetscFunctionReturn(0); 29 } 30 31 PETSC_STATIC_INLINE PetscInt epsilon(PetscInt i, PetscInt j, PetscInt k) 32 { 33 switch (i) { 34 case 0: 35 switch (j) { 36 case 0: return 0; 37 case 1: 38 switch (k) { 39 case 0: return 0; 40 case 1: return 0; 41 case 2: return 1; 42 } 43 case 2: 44 switch (k) { 45 case 0: return 0; 46 case 1: return -1; 47 case 2: return 0; 48 } 49 } 50 case 1: 51 switch (j) { 52 case 0: 53 switch (k) { 54 case 0: return 0; 55 case 1: return 0; 56 case 2: return -1; 57 } 58 case 1: return 0; 59 case 2: 60 switch (k) { 61 case 0: return 1; 62 case 1: return 0; 63 case 2: return 0; 64 } 65 } 66 case 2: 67 switch (j) { 68 case 0: 69 switch (k) { 70 case 0: return 0; 71 case 1: return 1; 72 case 2: return 0; 73 } 74 case 1: 75 switch (k) { 76 case 0: return -1; 77 case 1: return 0; 78 case 2: return 0; 79 } 80 case 2: return 0; 81 } 82 } 83 return 0; 84 } 85 86 #undef __FUNCT__ 87 #define __FUNCT__ "DMPlexCreateRigidBody" 88 /*@C 89 DMPlexCreateRigidBody - create rigid body modes from coordinates 90 91 Collective on DM 92 93 Input Arguments: 94 + dm - the DM 95 . section - the local section associated with the rigid field, or NULL for the default section 96 - globalSection - the global section associated with the rigid field, or NULL for the default section 97 98 Output Argument: 99 . sp - the null space 100 101 Note: This is necessary to take account of Dirichlet conditions on the displacements 102 103 Level: advanced 104 105 .seealso: MatNullSpaceCreate() 106 @*/ 107 PetscErrorCode DMPlexCreateRigidBody(DM dm, PetscSection section, PetscSection globalSection, MatNullSpace *sp) 108 { 109 MPI_Comm comm; 110 Vec coordinates, localMode, mode[6]; 111 PetscSection coordSection; 112 PetscScalar *coords; 113 PetscInt dim, vStart, vEnd, v, n, m, d, i, j; 114 PetscErrorCode ierr; 115 116 PetscFunctionBegin; 117 ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr); 118 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 119 if (dim == 1) { 120 ierr = MatNullSpaceCreate(comm, PETSC_TRUE, 0, NULL, sp);CHKERRQ(ierr); 121 PetscFunctionReturn(0); 122 } 123 if (!section) {ierr = DMGetDefaultSection(dm, §ion);CHKERRQ(ierr);} 124 if (!globalSection) {ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);} 125 ierr = PetscSectionGetConstrainedStorageSize(globalSection, &n);CHKERRQ(ierr); 126 ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr); 127 ierr = DMGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr); 128 ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr); 129 m = (dim*(dim+1))/2; 130 ierr = VecCreate(comm, &mode[0]);CHKERRQ(ierr); 131 ierr = VecSetSizes(mode[0], n, PETSC_DETERMINE);CHKERRQ(ierr); 132 ierr = VecSetUp(mode[0]);CHKERRQ(ierr); 133 for (i = 1; i < m; ++i) {ierr = VecDuplicate(mode[0], &mode[i]);CHKERRQ(ierr);} 134 /* Assume P1 */ 135 ierr = DMGetLocalVector(dm, &localMode);CHKERRQ(ierr); 136 for (d = 0; d < dim; ++d) { 137 PetscScalar values[3] = {0.0, 0.0, 0.0}; 138 139 values[d] = 1.0; 140 ierr = VecSet(localMode, 0.0);CHKERRQ(ierr); 141 for (v = vStart; v < vEnd; ++v) { 142 ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr); 143 } 144 ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr); 145 ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr); 146 } 147 ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr); 148 for (d = dim; d < dim*(dim+1)/2; ++d) { 149 PetscInt i, j, k = dim > 2 ? d - dim : d; 150 151 ierr = VecSet(localMode, 0.0);CHKERRQ(ierr); 152 for (v = vStart; v < vEnd; ++v) { 153 PetscScalar values[3] = {0.0, 0.0, 0.0}; 154 PetscInt off; 155 156 ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr); 157 for (i = 0; i < dim; ++i) { 158 for (j = 0; j < dim; ++j) { 159 values[j] += epsilon(i, j, k)*PetscRealPart(coords[off+i]); 160 } 161 } 162 ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr); 163 } 164 ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr); 165 ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr); 166 } 167 ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr); 168 ierr = DMRestoreLocalVector(dm, &localMode);CHKERRQ(ierr); 169 for (i = 0; i < dim; ++i) {ierr = VecNormalize(mode[i], NULL);CHKERRQ(ierr);} 170 /* Orthonormalize system */ 171 for (i = dim; i < m; ++i) { 172 PetscScalar dots[6]; 173 174 ierr = VecMDot(mode[i], i, mode, dots);CHKERRQ(ierr); 175 for (j = 0; j < i; ++j) dots[j] *= -1.0; 176 ierr = VecMAXPY(mode[i], i, dots, mode);CHKERRQ(ierr); 177 ierr = VecNormalize(mode[i], NULL);CHKERRQ(ierr); 178 } 179 ierr = MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp);CHKERRQ(ierr); 180 for (i = 0; i< m; ++i) {ierr = VecDestroy(&mode[i]);CHKERRQ(ierr);} 181 PetscFunctionReturn(0); 182 } 183 184 #undef __FUNCT__ 185 #define __FUNCT__ "DMPlexSetMaxProjectionHeight" 186 /*@ 187 DMPlexSetMaxProjectionHeight - In DMPlexProjectXXXLocal() functions, the projected values of a basis function's dofs 188 are computed by associating the basis function with one of the mesh points in its transitively-closed support, and 189 evaluating the dual space basis of that point. A basis function is associated with the point in its 190 transitively-closed support whose mesh height is highest (w.r.t. DAG height), but not greater than the maximum 191 projection height, which is set with this function. By default, the maximum projection height is zero, which means 192 that only mesh cells are used to project basis functions. A height of one, for example, evaluates a cell-interior 193 basis functions using its cells dual space basis, but all other basis functions with the dual space basis of a face. 194 195 Input Parameters: 196 + dm - the DMPlex object 197 - height - the maximum projection height >= 0 198 199 Level: advanced 200 201 .seealso: DMPlexGetMaxProjectionHeight(), DMPlexProjectFunctionLocal(), DMPlexProjectFunctionLabelLocal() 202 @*/ 203 PetscErrorCode DMPlexSetMaxProjectionHeight(DM dm, PetscInt height) 204 { 205 DM_Plex *plex = (DM_Plex *) dm->data; 206 207 PetscFunctionBegin; 208 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 209 plex->maxProjectionHeight = height; 210 PetscFunctionReturn(0); 211 } 212 213 #undef __FUNCT__ 214 #define __FUNCT__ "DMPlexGetMaxProjectionHeight" 215 /*@ 216 DMPlexGetMaxProjectionHeight - Get the maximum height (w.r.t. DAG) of mesh points used to evaluate dual bases in 217 DMPlexProjectXXXLocal() functions. 218 219 Input Parameters: 220 . dm - the DMPlex object 221 222 Output Parameters: 223 . height - the maximum projection height 224 225 Level: intermediate 226 227 .seealso: DMPlexSetMaxProjectionHeight(), DMPlexProjectFunctionLocal(), DMPlexProjectFunctionLabelLocal() 228 @*/ 229 PetscErrorCode DMPlexGetMaxProjectionHeight(DM dm, PetscInt *height) 230 { 231 DM_Plex *plex = (DM_Plex *) dm->data; 232 233 PetscFunctionBegin; 234 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 235 *height = plex->maxProjectionHeight; 236 PetscFunctionReturn(0); 237 } 238 239 #undef __FUNCT__ 240 #define __FUNCT__ "DMPlexProjectFunctionLabelLocal" 241 PetscErrorCode DMPlexProjectFunctionLabelLocal(DM dm, DMLabel label, PetscInt numIds, const PetscInt ids[], void (**funcs)(const PetscReal [], PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX) 242 { 243 PetscFE fe; 244 PetscDualSpace *sp, *cellsp; 245 PetscSection section; 246 PetscScalar *values; 247 PetscBool *fieldActive; 248 PetscInt numFields, numComp, dim, dimEmbed, spDim, totDim, numValues, pStart, pEnd, f, d, v, i, comp, maxHeight, h; 249 PetscErrorCode ierr; 250 251 PetscFunctionBegin; 252 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 253 ierr = DMGetCoordinateDim(dm, &dimEmbed);CHKERRQ(ierr); 254 ierr = DMGetDefaultSection(dm, §ion);CHKERRQ(ierr); 255 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 256 ierr = PetscMalloc1(numFields,&sp);CHKERRQ(ierr); 257 ierr = DMPlexGetMaxProjectionHeight(dm,&maxHeight);CHKERRQ(ierr); 258 if (maxHeight < 0 || maxHeight > dim) {SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_USER,"maximum projection height %d not in [0, %d)\n", maxHeight,dim);} 259 if (maxHeight > 0) { 260 ierr = PetscMalloc1(numFields,&cellsp);CHKERRQ(ierr); 261 } 262 else { 263 cellsp = sp; 264 } 265 for (h = 0; h <= maxHeight; h++) { 266 ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr); 267 if (pEnd <= pStart) continue; 268 totDim = 0; 269 for (f = 0; f < numFields; ++f) { 270 ierr = DMGetField(dm, f, (PetscObject *) &fe);CHKERRQ(ierr); 271 if (!h) { 272 ierr = PetscFEGetDualSpace(fe, &cellsp[f]);CHKERRQ(ierr); 273 sp[f] = cellsp[f]; 274 } 275 else { 276 ierr = PetscDualSpaceGetHeightSubspace(cellsp[f], h, &sp[f]);CHKERRQ(ierr); 277 if (!sp[f]) continue; 278 } 279 ierr = PetscFEGetNumComponents(fe, &numComp);CHKERRQ(ierr); 280 ierr = PetscDualSpaceGetDimension(sp[f], &spDim);CHKERRQ(ierr); 281 totDim += spDim*numComp; 282 } 283 ierr = DMPlexVecGetClosure(dm, section, localX, pStart, &numValues, NULL);CHKERRQ(ierr); 284 if (numValues != totDim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The section point closure size %d != dual space dimension %d", numValues, totDim); 285 if (!totDim) continue; 286 ierr = DMGetWorkArray(dm, numValues, PETSC_SCALAR, &values);CHKERRQ(ierr); 287 ierr = DMGetWorkArray(dm, numFields, PETSC_BOOL, &fieldActive);CHKERRQ(ierr); 288 for (f = 0; f < numFields; ++f) fieldActive[f] = (funcs[f] && sp[f]) ? PETSC_TRUE : PETSC_FALSE; 289 for (i = 0; i < numIds; ++i) { 290 IS pointIS; 291 const PetscInt *points; 292 PetscInt n, p; 293 294 ierr = DMLabelGetStratumIS(label, ids[i], &pointIS);CHKERRQ(ierr); 295 ierr = ISGetLocalSize(pointIS, &n);CHKERRQ(ierr); 296 ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr); 297 for (p = 0; p < n; ++p) { 298 const PetscInt point = points[p]; 299 PetscFECellGeom geom; 300 301 if ((point < pStart) || (point >= pEnd)) continue; 302 ierr = DMPlexComputeCellGeometryFEM(dm, point, NULL, geom.v0, geom.J, NULL, &geom.detJ);CHKERRQ(ierr); 303 geom.dim = dim - h; 304 geom.dimEmbed = dimEmbed; 305 for (f = 0, v = 0; f < numFields; ++f) { 306 void * const ctx = ctxs ? ctxs[f] : NULL; 307 308 if (!sp[f]) continue; 309 ierr = DMGetField(dm, f, (PetscObject *) &fe);CHKERRQ(ierr); 310 ierr = PetscFEGetNumComponents(fe, &numComp);CHKERRQ(ierr); 311 ierr = PetscDualSpaceGetDimension(sp[f], &spDim);CHKERRQ(ierr); 312 for (d = 0; d < spDim; ++d) { 313 if (funcs[f]) { 314 ierr = PetscDualSpaceApply(sp[f], d, &geom, numComp, funcs[f], ctx, &values[v]);CHKERRQ(ierr); 315 } else { 316 for (comp = 0; comp < numComp; ++comp) values[v+comp] = 0.0; 317 } 318 v += numComp; 319 } 320 } 321 ierr = DMPlexVecSetFieldClosure_Internal(dm, section, localX, fieldActive, point, values, mode);CHKERRQ(ierr); 322 } 323 ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr); 324 ierr = ISDestroy(&pointIS);CHKERRQ(ierr); 325 } 326 if (h) { 327 for (f = 0; f < numFields; ++f) {ierr = PetscDualSpaceDestroy(&sp[f]);CHKERRQ(ierr);} 328 } 329 } 330 ierr = DMRestoreWorkArray(dm, numValues, PETSC_SCALAR, &values);CHKERRQ(ierr); 331 ierr = DMRestoreWorkArray(dm, numFields, PETSC_BOOL, &fieldActive);CHKERRQ(ierr); 332 ierr = PetscFree(sp);CHKERRQ(ierr); 333 if (maxHeight > 0) { 334 ierr = PetscFree(cellsp);CHKERRQ(ierr); 335 } 336 PetscFunctionReturn(0); 337 } 338 339 #undef __FUNCT__ 340 #define __FUNCT__ "DMPlexProjectFunctionLocal" 341 PetscErrorCode DMPlexProjectFunctionLocal(DM dm, void (**funcs)(const PetscReal [], PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX) 342 { 343 PetscDualSpace *sp, *cellsp; 344 PetscInt *numComp; 345 PetscSection section; 346 PetscScalar *values; 347 PetscInt numFields, dim, dimEmbed, spDim, totDim, numValues, pStart, pEnd, p, f, d, v, comp, h, maxHeight; 348 PetscErrorCode ierr; 349 350 PetscFunctionBegin; 351 ierr = DMGetDefaultSection(dm, §ion);CHKERRQ(ierr); 352 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 353 ierr = PetscMalloc2(numFields, &sp, numFields, &numComp);CHKERRQ(ierr); 354 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 355 ierr = DMGetCoordinateDim(dm, &dimEmbed);CHKERRQ(ierr); 356 ierr = DMPlexGetMaxProjectionHeight(dm,&maxHeight);CHKERRQ(ierr); 357 if (maxHeight < 0 || maxHeight > dim) {SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_USER,"maximum projection height %d not in [0, %d)\n", maxHeight,dim);} 358 if (maxHeight > 0) { 359 ierr = PetscMalloc1(numFields,&cellsp);CHKERRQ(ierr); 360 } 361 else { 362 cellsp = sp; 363 } 364 for (h = 0; h <= maxHeight; h++) { 365 ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr); 366 if (pEnd <= pStart) continue; 367 totDim = 0; 368 for (f = 0; f < numFields; ++f) { 369 PetscObject obj; 370 PetscClassId id; 371 372 ierr = DMGetField(dm, f, &obj);CHKERRQ(ierr); 373 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 374 if (id == PETSCFE_CLASSID) { 375 PetscFE fe = (PetscFE) obj; 376 377 ierr = PetscFEGetNumComponents(fe, &numComp[f]);CHKERRQ(ierr); 378 if (!h) { 379 ierr = PetscFEGetDualSpace(fe, &cellsp[f]);CHKERRQ(ierr); 380 sp[f] = cellsp[f]; 381 ierr = PetscObjectReference((PetscObject) sp[f]);CHKERRQ(ierr); 382 } 383 else { 384 ierr = PetscDualSpaceGetHeightSubspace(cellsp[f], h, &sp[f]);CHKERRQ(ierr); 385 if (!sp[f]) { 386 continue; 387 } 388 } 389 } else if (id == PETSCFV_CLASSID) { 390 PetscFV fv = (PetscFV) obj; 391 PetscQuadrature q; 392 393 if (h) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP, "Projection height > 0 not supported for finite volume"); 394 ierr = PetscFVGetNumComponents(fv, &numComp[f]);CHKERRQ(ierr); 395 ierr = PetscFVGetQuadrature(fv, &q);CHKERRQ(ierr); 396 ierr = PetscDualSpaceCreate(PetscObjectComm((PetscObject) fv), &sp[f]);CHKERRQ(ierr); 397 ierr = PetscDualSpaceSetDM(sp[f], dm);CHKERRQ(ierr); 398 ierr = PetscDualSpaceSetType(sp[f], PETSCDUALSPACESIMPLE);CHKERRQ(ierr); 399 ierr = PetscDualSpaceSimpleSetDimension(sp[f], 1);CHKERRQ(ierr); 400 ierr = PetscDualSpaceSimpleSetFunctional(sp[f], 0, q);CHKERRQ(ierr); 401 } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", f); 402 ierr = PetscDualSpaceGetDimension(sp[f], &spDim);CHKERRQ(ierr); 403 totDim += spDim*numComp[f]; 404 } 405 ierr = DMPlexVecGetClosure(dm, section, localX, pStart, &numValues, NULL);CHKERRQ(ierr); 406 if (numValues != totDim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The section point closure size %d != dual space dimension %d", numValues, totDim); 407 if (!totDim) continue; 408 ierr = DMGetWorkArray(dm, numValues, PETSC_SCALAR, &values);CHKERRQ(ierr); 409 for (p = pStart; p < pEnd; ++p) { 410 PetscFECellGeom geom; 411 412 ierr = DMPlexComputeCellGeometryFEM(dm, p, NULL, geom.v0, geom.J, NULL, &geom.detJ);CHKERRQ(ierr); 413 geom.dim = dim - h; 414 geom.dimEmbed = dimEmbed; 415 for (f = 0, v = 0; f < numFields; ++f) { 416 void * const ctx = ctxs ? ctxs[f] : NULL; 417 418 if (!sp[f]) continue; 419 ierr = PetscDualSpaceGetDimension(sp[f], &spDim);CHKERRQ(ierr); 420 for (d = 0; d < spDim; ++d) { 421 if (funcs[f]) { 422 ierr = PetscDualSpaceApply(sp[f], d, &geom, numComp[f], funcs[f], ctx, &values[v]);CHKERRQ(ierr); 423 } else { 424 for (comp = 0; comp < numComp[f]; ++comp) values[v+comp] = 0.0; 425 } 426 v += numComp[f]; 427 } 428 } 429 ierr = DMPlexVecSetClosure(dm, section, localX, p, values, mode);CHKERRQ(ierr); 430 } 431 ierr = DMRestoreWorkArray(dm, numValues, PETSC_SCALAR, &values);CHKERRQ(ierr); 432 if (h || !maxHeight) { 433 for (f = 0; f < numFields; f++) {ierr = PetscDualSpaceDestroy(&sp[f]);CHKERRQ(ierr);} 434 } 435 } 436 ierr = PetscFree2(sp, numComp);CHKERRQ(ierr); 437 if (maxHeight > 0) { 438 for (f = 0; f < numFields; f++) {ierr = PetscDualSpaceDestroy(&cellsp[f]);CHKERRQ(ierr);} 439 ierr = PetscFree(cellsp);CHKERRQ(ierr); 440 } 441 PetscFunctionReturn(0); 442 } 443 444 #undef __FUNCT__ 445 #define __FUNCT__ "DMPlexProjectFunction" 446 /*@C 447 DMPlexProjectFunction - This projects the given function into the function space provided. 448 449 Input Parameters: 450 + dm - The DM 451 . funcs - The coordinate functions to evaluate, one per field 452 . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null. 453 - mode - The insertion mode for values 454 455 Output Parameter: 456 . X - vector 457 458 Level: developer 459 460 .seealso: DMPlexComputeL2Diff() 461 @*/ 462 PetscErrorCode DMPlexProjectFunction(DM dm, void (**funcs)(const PetscReal [], PetscScalar *, void *), void **ctxs, InsertMode mode, Vec X) 463 { 464 Vec localX; 465 PetscErrorCode ierr; 466 467 PetscFunctionBegin; 468 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 469 ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr); 470 ierr = DMPlexProjectFunctionLocal(dm, funcs, ctxs, mode, localX);CHKERRQ(ierr); 471 ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr); 472 ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr); 473 ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr); 474 PetscFunctionReturn(0); 475 } 476 477 #undef __FUNCT__ 478 #define __FUNCT__ "DMPlexProjectFieldLocal" 479 PetscErrorCode DMPlexProjectFieldLocal(DM dm, Vec localU, void (**funcs)(const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscReal [], PetscScalar []), InsertMode mode, Vec localX) 480 { 481 DM dmAux; 482 PetscDS prob, probAux; 483 Vec A; 484 PetscSection section, sectionAux; 485 PetscScalar *values, *u, *u_x, *a, *a_x; 486 PetscReal *x, *v0, *J, *invJ, detJ, **basisField, **basisFieldDer, **basisFieldAux, **basisFieldDerAux; 487 PetscInt Nf, dim, spDim, totDim, numValues, cStart, cEnd, c, f, d, v, comp, maxHeight; 488 PetscErrorCode ierr; 489 490 PetscFunctionBegin; 491 ierr = DMPlexGetMaxProjectionHeight(dm,&maxHeight);CHKERRQ(ierr); 492 if (maxHeight > 0) {SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Field projection for height > 0 not supported yet");} 493 ierr = DMGetDS(dm, &prob);CHKERRQ(ierr); 494 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 495 ierr = DMGetDefaultSection(dm, §ion);CHKERRQ(ierr); 496 ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr); 497 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 498 ierr = PetscDSGetTotalDimension(prob, &totDim);CHKERRQ(ierr); 499 ierr = PetscDSGetTabulation(prob, &basisField, &basisFieldDer);CHKERRQ(ierr); 500 ierr = PetscDSGetEvaluationArrays(prob, &u, NULL, &u_x);CHKERRQ(ierr); 501 ierr = PetscDSGetRefCoordArrays(prob, &x, NULL);CHKERRQ(ierr); 502 ierr = PetscObjectQuery((PetscObject) dm, "dmAux", (PetscObject *) &dmAux);CHKERRQ(ierr); 503 ierr = PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &A);CHKERRQ(ierr); 504 if (dmAux) { 505 ierr = DMGetDS(dmAux, &probAux);CHKERRQ(ierr); 506 ierr = DMGetDefaultSection(dmAux, §ionAux);CHKERRQ(ierr); 507 ierr = PetscDSGetTabulation(prob, &basisFieldAux, &basisFieldDerAux);CHKERRQ(ierr); 508 ierr = PetscDSGetEvaluationArrays(probAux, &a, NULL, &a_x);CHKERRQ(ierr); 509 } 510 ierr = DMPlexInsertBoundaryValues(dm, localU, 0.0, NULL, NULL, NULL);CHKERRQ(ierr); 511 ierr = DMPlexVecGetClosure(dm, section, localX, cStart, &numValues, NULL);CHKERRQ(ierr); 512 if (numValues != totDim) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "The section cell closure size %d != dual space dimension %d", numValues, totDim); 513 ierr = DMGetWorkArray(dm, numValues, PETSC_SCALAR, &values);CHKERRQ(ierr); 514 ierr = PetscMalloc3(dim,&v0,dim*dim,&J,dim*dim,&invJ);CHKERRQ(ierr); 515 for (c = cStart; c < cEnd; ++c) { 516 PetscScalar *coefficients = NULL, *coefficientsAux = NULL; 517 518 ierr = DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, invJ, &detJ);CHKERRQ(ierr); 519 ierr = DMPlexVecGetClosure(dm, section, localU, c, NULL, &coefficients);CHKERRQ(ierr); 520 if (dmAux) {ierr = DMPlexVecGetClosure(dmAux, sectionAux, A, c, NULL, &coefficientsAux);CHKERRQ(ierr);} 521 for (f = 0, v = 0; f < Nf; ++f) { 522 PetscFE fe; 523 PetscDualSpace sp; 524 PetscInt Ncf; 525 526 ierr = PetscDSGetDiscretization(prob, f, (PetscObject *) &fe);CHKERRQ(ierr); 527 ierr = PetscFEGetDualSpace(fe, &sp);CHKERRQ(ierr); 528 ierr = PetscFEGetNumComponents(fe, &Ncf);CHKERRQ(ierr); 529 ierr = PetscDualSpaceGetDimension(sp, &spDim);CHKERRQ(ierr); 530 for (d = 0; d < spDim; ++d) { 531 PetscQuadrature quad; 532 const PetscReal *points, *weights; 533 PetscInt numPoints, q; 534 535 if (funcs[f]) { 536 ierr = PetscDualSpaceGetFunctional(sp, d, &quad);CHKERRQ(ierr); 537 ierr = PetscQuadratureGetData(quad, NULL, &numPoints, &points, &weights);CHKERRQ(ierr); 538 ierr = PetscFEGetTabulation(fe, numPoints, points, &basisField[f], &basisFieldDer[f], NULL);CHKERRQ(ierr); 539 for (q = 0; q < numPoints; ++q) { 540 CoordinatesRefToReal(dim, dim, v0, J, &points[q*dim], x); 541 ierr = EvaluateFieldJets(prob, PETSC_FALSE, q, invJ, coefficients, NULL, u, u_x, NULL);CHKERRQ(ierr); 542 ierr = EvaluateFieldJets(probAux, PETSC_FALSE, q, invJ, coefficientsAux, NULL, a, a_x, NULL);CHKERRQ(ierr); 543 (*funcs[f])(u, NULL, u_x, a, NULL, a_x, x, &values[v]); 544 } 545 ierr = PetscFERestoreTabulation(fe, numPoints, points, &basisField[f], &basisFieldDer[f], NULL);CHKERRQ(ierr); 546 } else { 547 for (comp = 0; comp < Ncf; ++comp) values[v+comp] = 0.0; 548 } 549 v += Ncf; 550 } 551 } 552 ierr = DMPlexVecRestoreClosure(dm, section, localU, c, NULL, &coefficients);CHKERRQ(ierr); 553 if (dmAux) {ierr = DMPlexVecRestoreClosure(dmAux, sectionAux, A, c, NULL, &coefficientsAux);CHKERRQ(ierr);} 554 ierr = DMPlexVecSetClosure(dm, section, localX, c, values, mode);CHKERRQ(ierr); 555 } 556 ierr = DMRestoreWorkArray(dm, numValues, PETSC_SCALAR, &values);CHKERRQ(ierr); 557 ierr = PetscFree3(v0,J,invJ);CHKERRQ(ierr); 558 PetscFunctionReturn(0); 559 } 560 561 #undef __FUNCT__ 562 #define __FUNCT__ "DMPlexInsertBoundaryValues_FEM_Internal" 563 static PetscErrorCode DMPlexInsertBoundaryValues_FEM_Internal(DM dm, PetscInt field, DMLabel label, PetscInt numids, const PetscInt ids[], void (*func)(const PetscReal[], PetscScalar *, void *), void *ctx, Vec locX) 564 { 565 void (**funcs)(const PetscReal x[], PetscScalar *u, void *ctx); 566 void **ctxs; 567 PetscInt numFields; 568 PetscErrorCode ierr; 569 570 PetscFunctionBegin; 571 ierr = DMGetNumFields(dm, &numFields);CHKERRQ(ierr); 572 ierr = PetscCalloc2(numFields,&funcs,numFields,&ctxs);CHKERRQ(ierr); 573 funcs[field] = func; 574 ctxs[field] = ctx; 575 ierr = DMPlexProjectFunctionLabelLocal(dm, label, numids, ids, funcs, ctxs, INSERT_BC_VALUES, locX);CHKERRQ(ierr); 576 ierr = PetscFree2(funcs,ctxs);CHKERRQ(ierr); 577 PetscFunctionReturn(0); 578 } 579 580 #undef __FUNCT__ 581 #define __FUNCT__ "DMPlexInsertBoundaryValues_FVM_Internal" 582 static PetscErrorCode DMPlexInsertBoundaryValues_FVM_Internal(DM dm, PetscReal time, Vec faceGeometry, Vec cellGeometry, Vec Grad, 583 PetscInt field, DMLabel label, PetscInt numids, const PetscInt ids[], PetscErrorCode (*func)(PetscReal,const PetscReal*,const PetscReal*,const PetscScalar*,PetscScalar*,void*), void *ctx, Vec locX) 584 { 585 PetscFV fv; 586 DM dmFace, dmCell, dmGrad; 587 const PetscScalar *facegeom, *cellgeom, *grad; 588 PetscScalar *x, *fx; 589 PetscInt dim, fStart, fEnd, pdim, i; 590 PetscErrorCode ierr; 591 592 PetscFunctionBegin; 593 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 594 ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr); 595 ierr = DMGetField(dm, field, (PetscObject *) &fv);CHKERRQ(ierr); 596 ierr = VecGetDM(faceGeometry, &dmFace);CHKERRQ(ierr); 597 ierr = VecGetArrayRead(faceGeometry, &facegeom);CHKERRQ(ierr); 598 ierr = VecGetDM(cellGeometry, &dmCell);CHKERRQ(ierr); 599 ierr = VecGetArrayRead(cellGeometry, &cellgeom);CHKERRQ(ierr); 600 if (Grad) { 601 ierr = VecGetDM(Grad, &dmGrad);CHKERRQ(ierr); 602 ierr = VecGetArrayRead(Grad, &grad);CHKERRQ(ierr); 603 ierr = PetscFVGetNumComponents(fv, &pdim);CHKERRQ(ierr); 604 ierr = DMGetWorkArray(dm, pdim, PETSC_SCALAR, &fx);CHKERRQ(ierr); 605 } 606 ierr = VecGetArray(locX, &x);CHKERRQ(ierr); 607 for (i = 0; i < numids; ++i) { 608 IS faceIS; 609 const PetscInt *faces; 610 PetscInt numFaces, f; 611 612 ierr = DMLabelGetStratumIS(label, ids[i], &faceIS);CHKERRQ(ierr); 613 if (!faceIS) continue; /* No points with that id on this process */ 614 ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr); 615 ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr); 616 for (f = 0; f < numFaces; ++f) { 617 const PetscInt face = faces[f], *cells; 618 const PetscFVFaceGeom *fg; 619 620 if ((face < fStart) || (face >= fEnd)) continue; /* Refinement adds non-faces to labels */ 621 ierr = DMPlexPointLocalRead(dmFace, face, facegeom, &fg);CHKERRQ(ierr); 622 ierr = DMPlexGetSupport(dm, face, &cells);CHKERRQ(ierr); 623 if (Grad) { 624 const PetscFVCellGeom *cg; 625 const PetscScalar *cx, *cgrad; 626 PetscScalar *xG; 627 PetscReal dx[3]; 628 PetscInt d; 629 630 ierr = DMPlexPointLocalRead(dmCell, cells[0], cellgeom, &cg);CHKERRQ(ierr); 631 ierr = DMPlexPointLocalRead(dm, cells[0], x, &cx);CHKERRQ(ierr); 632 ierr = DMPlexPointLocalRead(dmGrad, cells[0], grad, &cgrad);CHKERRQ(ierr); 633 ierr = DMPlexPointLocalRef(dm, cells[1], x, &xG);CHKERRQ(ierr); 634 DMPlex_WaxpyD_Internal(dim, -1, cg->centroid, fg->centroid, dx); 635 for (d = 0; d < pdim; ++d) fx[d] = cx[d] + DMPlex_DotD_Internal(dim, &cgrad[d*dim], dx); 636 ierr = (*func)(time, fg->centroid, fg->normal, fx, xG, ctx);CHKERRQ(ierr); 637 } else { 638 const PetscScalar *xI; 639 PetscScalar *xG; 640 641 ierr = DMPlexPointLocalRead(dm, cells[0], x, &xI);CHKERRQ(ierr); 642 ierr = DMPlexPointLocalRef(dm, cells[1], x, &xG);CHKERRQ(ierr); 643 ierr = (*func)(time, fg->centroid, fg->normal, xI, xG, ctx);CHKERRQ(ierr); 644 } 645 } 646 ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr); 647 ierr = ISDestroy(&faceIS);CHKERRQ(ierr); 648 } 649 ierr = VecRestoreArray(locX, &x);CHKERRQ(ierr); 650 if (Grad) { 651 ierr = DMRestoreWorkArray(dm, pdim, PETSC_SCALAR, &fx);CHKERRQ(ierr); 652 ierr = VecRestoreArrayRead(Grad, &grad);CHKERRQ(ierr); 653 } 654 ierr = VecRestoreArrayRead(cellGeometry, &cellgeom);CHKERRQ(ierr); 655 ierr = VecRestoreArrayRead(faceGeometry, &facegeom);CHKERRQ(ierr); 656 PetscFunctionReturn(0); 657 } 658 659 #undef __FUNCT__ 660 #define __FUNCT__ "DMPlexInsertBoundaryValues" 661 PetscErrorCode DMPlexInsertBoundaryValues(DM dm, Vec locX, PetscReal time, Vec faceGeomFVM, Vec cellGeomFVM, Vec gradFVM) 662 { 663 PetscInt numBd, b; 664 PetscErrorCode ierr; 665 666 PetscFunctionBegin; 667 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 668 PetscValidHeaderSpecific(locX, VEC_CLASSID, 2); 669 if (faceGeomFVM) {PetscValidHeaderSpecific(faceGeomFVM, VEC_CLASSID, 4);} 670 if (cellGeomFVM) {PetscValidHeaderSpecific(cellGeomFVM, VEC_CLASSID, 5);} 671 if (gradFVM) {PetscValidHeaderSpecific(gradFVM, VEC_CLASSID, 6);} 672 ierr = DMPlexGetNumBoundary(dm, &numBd);CHKERRQ(ierr); 673 for (b = 0; b < numBd; ++b) { 674 PetscBool isEssential; 675 const char *labelname; 676 DMLabel label; 677 PetscInt field; 678 PetscObject obj; 679 PetscClassId id; 680 void (*func)(); 681 PetscInt numids; 682 const PetscInt *ids; 683 void *ctx; 684 685 ierr = DMPlexGetBoundary(dm, b, &isEssential, NULL, &labelname, &field, &func, &numids, &ids, &ctx);CHKERRQ(ierr); 686 if (!isEssential) continue; 687 ierr = DMPlexGetLabel(dm, labelname, &label);CHKERRQ(ierr); 688 ierr = DMGetField(dm, field, &obj);CHKERRQ(ierr); 689 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 690 if (id == PETSCFE_CLASSID) { 691 ierr = DMPlexInsertBoundaryValues_FEM_Internal(dm, field, label, numids, ids, (void (*)(const PetscReal[], PetscScalar *, void *)) func, ctx, locX);CHKERRQ(ierr); 692 } else if (id == PETSCFV_CLASSID) { 693 ierr = DMPlexInsertBoundaryValues_FVM_Internal(dm, time, faceGeomFVM, cellGeomFVM, gradFVM, 694 field, label, numids, ids, (PetscErrorCode (*)(PetscReal,const PetscReal*,const PetscReal*,const PetscScalar*,PetscScalar*,void*)) func, ctx, locX);CHKERRQ(ierr); 695 } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field); 696 } 697 PetscFunctionReturn(0); 698 } 699 700 #undef __FUNCT__ 701 #define __FUNCT__ "DMPlexComputeL2Diff" 702 /*@C 703 DMPlexComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h. 704 705 Input Parameters: 706 + dm - The DM 707 . funcs - The functions to evaluate for each field component 708 . ctxs - Optional array of contexts to pass to each function, or NULL. 709 - X - The coefficient vector u_h 710 711 Output Parameter: 712 . diff - The diff ||u - u_h||_2 713 714 Level: developer 715 716 .seealso: DMPlexProjectFunction(), DMPlexComputeL2FieldDiff(), DMPlexComputeL2GradientDiff() 717 @*/ 718 PetscErrorCode DMPlexComputeL2Diff(DM dm, void (**funcs)(const PetscReal [], PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff) 719 { 720 const PetscInt debug = 0; 721 PetscSection section; 722 PetscQuadrature quad; 723 Vec localX; 724 PetscScalar *funcVal, *interpolant; 725 PetscReal *coords, *v0, *J, *invJ, detJ; 726 PetscReal localDiff = 0.0; 727 const PetscReal *quadPoints, *quadWeights; 728 PetscInt dim, numFields, numComponents = 0, numQuadPoints, cStart, cEnd, c, field, fieldOffset; 729 PetscErrorCode ierr; 730 731 PetscFunctionBegin; 732 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 733 ierr = DMGetDefaultSection(dm, §ion);CHKERRQ(ierr); 734 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 735 ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr); 736 ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr); 737 ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr); 738 for (field = 0; field < numFields; ++field) { 739 PetscObject obj; 740 PetscClassId id; 741 PetscInt Nc; 742 743 ierr = DMGetField(dm, field, &obj);CHKERRQ(ierr); 744 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 745 if (id == PETSCFE_CLASSID) { 746 PetscFE fe = (PetscFE) obj; 747 748 ierr = PetscFEGetQuadrature(fe, &quad);CHKERRQ(ierr); 749 ierr = PetscFEGetNumComponents(fe, &Nc);CHKERRQ(ierr); 750 } else if (id == PETSCFV_CLASSID) { 751 PetscFV fv = (PetscFV) obj; 752 753 ierr = PetscFVGetQuadrature(fv, &quad);CHKERRQ(ierr); 754 ierr = PetscFVGetNumComponents(fv, &Nc);CHKERRQ(ierr); 755 } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field); 756 numComponents += Nc; 757 } 758 ierr = PetscQuadratureGetData(quad, NULL, &numQuadPoints, &quadPoints, &quadWeights);CHKERRQ(ierr); 759 ierr = DMPlexProjectFunctionLocal(dm, funcs, ctxs, INSERT_BC_VALUES, localX);CHKERRQ(ierr); 760 ierr = PetscMalloc6(numComponents,&funcVal,numComponents,&interpolant,dim,&coords,dim,&v0,dim*dim,&J,dim*dim,&invJ);CHKERRQ(ierr); 761 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 762 for (c = cStart; c < cEnd; ++c) { 763 PetscScalar *x = NULL; 764 PetscReal elemDiff = 0.0; 765 766 ierr = DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, invJ, &detJ);CHKERRQ(ierr); 767 if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ, c); 768 ierr = DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr); 769 770 for (field = 0, fieldOffset = 0; field < numFields; ++field) { 771 PetscObject obj; 772 PetscClassId id; 773 void * const ctx = ctxs ? ctxs[field] : NULL; 774 PetscInt Nb, Nc, q, fc; 775 776 ierr = DMGetField(dm, field, &obj);CHKERRQ(ierr); 777 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 778 if (id == PETSCFE_CLASSID) {ierr = PetscFEGetNumComponents((PetscFE) obj, &Nc);CHKERRQ(ierr);ierr = PetscFEGetDimension((PetscFE) obj, &Nb);CHKERRQ(ierr);} 779 else if (id == PETSCFV_CLASSID) {ierr = PetscFVGetNumComponents((PetscFV) obj, &Nc);CHKERRQ(ierr);Nb = 1;} 780 else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field); 781 if (debug) { 782 char title[1024]; 783 ierr = PetscSNPrintf(title, 1023, "Solution for Field %d", field);CHKERRQ(ierr); 784 ierr = DMPrintCellVector(c, title, Nb*Nc, &x[fieldOffset]);CHKERRQ(ierr); 785 } 786 for (q = 0; q < numQuadPoints; ++q) { 787 CoordinatesRefToReal(dim, dim, v0, J, &quadPoints[q*dim], coords); 788 (*funcs[field])(coords, funcVal, ctx); 789 if (id == PETSCFE_CLASSID) {ierr = PetscFEInterpolate_Static((PetscFE) obj, &x[fieldOffset], q, interpolant);CHKERRQ(ierr);} 790 else if (id == PETSCFV_CLASSID) {ierr = PetscFVInterpolate_Static((PetscFV) obj, &x[fieldOffset], q, interpolant);CHKERRQ(ierr);} 791 else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field); 792 for (fc = 0; fc < Nc; ++fc) { 793 if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, " elem %d field %d diff %g\n", c, field, PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc]))*quadWeights[q]*detJ);CHKERRQ(ierr);} 794 elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc]))*quadWeights[q]*detJ; 795 } 796 } 797 fieldOffset += Nb*Nc; 798 } 799 ierr = DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr); 800 if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, " elem %d diff %g\n", c, elemDiff);CHKERRQ(ierr);} 801 localDiff += elemDiff; 802 } 803 ierr = PetscFree6(funcVal,interpolant,coords,v0,J,invJ);CHKERRQ(ierr); 804 ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr); 805 ierr = MPI_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPI_SUM, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr); 806 *diff = PetscSqrtReal(*diff); 807 PetscFunctionReturn(0); 808 } 809 810 #undef __FUNCT__ 811 #define __FUNCT__ "DMPlexComputeL2GradientDiff" 812 /*@C 813 DMPlexComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h. 814 815 Input Parameters: 816 + dm - The DM 817 . funcs - The gradient functions to evaluate for each field component 818 . ctxs - Optional array of contexts to pass to each function, or NULL. 819 . X - The coefficient vector u_h 820 - n - The vector to project along 821 822 Output Parameter: 823 . diff - The diff ||(grad u - grad u_h) . n||_2 824 825 Level: developer 826 827 .seealso: DMPlexProjectFunction(), DMPlexComputeL2Diff() 828 @*/ 829 PetscErrorCode DMPlexComputeL2GradientDiff(DM dm, void (**funcs)(const PetscReal [], const PetscReal [], PetscScalar *, void *), void **ctxs, Vec X, const PetscReal n[], PetscReal *diff) 830 { 831 const PetscInt debug = 0; 832 PetscSection section; 833 PetscQuadrature quad; 834 Vec localX; 835 PetscScalar *funcVal, *interpolantVec; 836 PetscReal *coords, *realSpaceDer, *v0, *J, *invJ, detJ; 837 PetscReal localDiff = 0.0; 838 PetscInt dim, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset, comp; 839 PetscErrorCode ierr; 840 841 PetscFunctionBegin; 842 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 843 ierr = DMGetDefaultSection(dm, §ion);CHKERRQ(ierr); 844 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 845 ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr); 846 ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr); 847 ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr); 848 for (field = 0; field < numFields; ++field) { 849 PetscFE fe; 850 PetscInt Nc; 851 852 ierr = DMGetField(dm, field, (PetscObject *) &fe);CHKERRQ(ierr); 853 ierr = PetscFEGetQuadrature(fe, &quad);CHKERRQ(ierr); 854 ierr = PetscFEGetNumComponents(fe, &Nc);CHKERRQ(ierr); 855 numComponents += Nc; 856 } 857 /* ierr = DMPlexProjectFunctionLocal(dm, fe, funcs, INSERT_BC_VALUES, localX);CHKERRQ(ierr); */ 858 ierr = PetscMalloc7(numComponents,&funcVal,dim,&coords,dim,&realSpaceDer,dim,&v0,dim*dim,&J,dim*dim,&invJ,dim,&interpolantVec);CHKERRQ(ierr); 859 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 860 for (c = cStart; c < cEnd; ++c) { 861 PetscScalar *x = NULL; 862 PetscReal elemDiff = 0.0; 863 864 ierr = DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, invJ, &detJ);CHKERRQ(ierr); 865 if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ, c); 866 ierr = DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr); 867 868 for (field = 0, comp = 0, fieldOffset = 0; field < numFields; ++field) { 869 PetscFE fe; 870 void * const ctx = ctxs ? ctxs[field] : NULL; 871 const PetscReal *quadPoints, *quadWeights; 872 PetscReal *basisDer; 873 PetscInt numQuadPoints, Nb, Ncomp, q, d, e, fc, f, g; 874 875 ierr = DMGetField(dm, field, (PetscObject *) &fe);CHKERRQ(ierr); 876 ierr = PetscQuadratureGetData(quad, NULL, &numQuadPoints, &quadPoints, &quadWeights);CHKERRQ(ierr); 877 ierr = PetscFEGetDimension(fe, &Nb);CHKERRQ(ierr); 878 ierr = PetscFEGetNumComponents(fe, &Ncomp);CHKERRQ(ierr); 879 ierr = PetscFEGetDefaultTabulation(fe, NULL, &basisDer, NULL);CHKERRQ(ierr); 880 if (debug) { 881 char title[1024]; 882 ierr = PetscSNPrintf(title, 1023, "Solution for Field %d", field);CHKERRQ(ierr); 883 ierr = DMPrintCellVector(c, title, Nb*Ncomp, &x[fieldOffset]);CHKERRQ(ierr); 884 } 885 for (q = 0; q < numQuadPoints; ++q) { 886 for (d = 0; d < dim; d++) { 887 coords[d] = v0[d]; 888 for (e = 0; e < dim; e++) { 889 coords[d] += J[d*dim+e]*(quadPoints[q*dim+e] + 1.0); 890 } 891 } 892 (*funcs[field])(coords, n, funcVal, ctx); 893 for (fc = 0; fc < Ncomp; ++fc) { 894 PetscScalar interpolant = 0.0; 895 896 for (d = 0; d < dim; ++d) interpolantVec[d] = 0.0; 897 for (f = 0; f < Nb; ++f) { 898 const PetscInt fidx = f*Ncomp+fc; 899 900 for (d = 0; d < dim; ++d) { 901 realSpaceDer[d] = 0.0; 902 for (g = 0; g < dim; ++g) { 903 realSpaceDer[d] += invJ[g*dim+d]*basisDer[(q*Nb*Ncomp+fidx)*dim+g]; 904 } 905 interpolantVec[d] += x[fieldOffset+fidx]*realSpaceDer[d]; 906 } 907 } 908 for (d = 0; d < dim; ++d) interpolant += interpolantVec[d]*n[d]; 909 if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, " elem %d fieldDer %d diff %g\n", c, field, PetscSqr(PetscRealPart(interpolant - funcVal[fc]))*quadWeights[q]*detJ);CHKERRQ(ierr);} 910 elemDiff += PetscSqr(PetscRealPart(interpolant - funcVal[fc]))*quadWeights[q]*detJ; 911 } 912 } 913 comp += Ncomp; 914 fieldOffset += Nb*Ncomp; 915 } 916 ierr = DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr); 917 if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, " elem %d diff %g\n", c, elemDiff);CHKERRQ(ierr);} 918 localDiff += elemDiff; 919 } 920 ierr = PetscFree7(funcVal,coords,realSpaceDer,v0,J,invJ,interpolantVec);CHKERRQ(ierr); 921 ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr); 922 ierr = MPI_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPI_SUM, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr); 923 *diff = PetscSqrtReal(*diff); 924 PetscFunctionReturn(0); 925 } 926 927 #undef __FUNCT__ 928 #define __FUNCT__ "DMPlexComputeL2FieldDiff" 929 /*@C 930 DMPlexComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components. 931 932 Input Parameters: 933 + dm - The DM 934 . funcs - The functions to evaluate for each field component 935 . ctxs - Optional array of contexts to pass to each function, or NULL. 936 - X - The coefficient vector u_h 937 938 Output Parameter: 939 . diff - The array of differences, ||u^f - u^f_h||_2 940 941 Level: developer 942 943 .seealso: DMPlexProjectFunction(), DMPlexComputeL2Diff(), DMPlexComputeL2GradientDiff() 944 @*/ 945 PetscErrorCode DMPlexComputeL2FieldDiff(DM dm, void (**funcs)(const PetscReal [], PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[]) 946 { 947 const PetscInt debug = 0; 948 PetscSection section; 949 PetscQuadrature quad; 950 Vec localX; 951 PetscScalar *funcVal, *interpolant; 952 PetscReal *coords, *v0, *J, *invJ, detJ; 953 PetscReal *localDiff; 954 const PetscReal *quadPoints, *quadWeights; 955 PetscInt dim, numFields, numComponents = 0, numQuadPoints, cStart, cEnd, c, field, fieldOffset; 956 PetscErrorCode ierr; 957 958 PetscFunctionBegin; 959 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 960 ierr = DMGetDefaultSection(dm, §ion);CHKERRQ(ierr); 961 ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr); 962 ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr); 963 ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr); 964 ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr); 965 for (field = 0; field < numFields; ++field) { 966 PetscObject obj; 967 PetscClassId id; 968 PetscInt Nc; 969 970 ierr = DMGetField(dm, field, &obj);CHKERRQ(ierr); 971 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 972 if (id == PETSCFE_CLASSID) { 973 PetscFE fe = (PetscFE) obj; 974 975 ierr = PetscFEGetQuadrature(fe, &quad);CHKERRQ(ierr); 976 ierr = PetscFEGetNumComponents(fe, &Nc);CHKERRQ(ierr); 977 } else if (id == PETSCFV_CLASSID) { 978 PetscFV fv = (PetscFV) obj; 979 980 ierr = PetscFVGetQuadrature(fv, &quad);CHKERRQ(ierr); 981 ierr = PetscFVGetNumComponents(fv, &Nc);CHKERRQ(ierr); 982 } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field); 983 numComponents += Nc; 984 } 985 ierr = PetscQuadratureGetData(quad, NULL, &numQuadPoints, &quadPoints, &quadWeights);CHKERRQ(ierr); 986 ierr = DMPlexProjectFunctionLocal(dm, funcs, ctxs, INSERT_BC_VALUES, localX);CHKERRQ(ierr); 987 ierr = PetscCalloc7(numFields,&localDiff,numComponents,&funcVal,numComponents,&interpolant,dim,&coords,dim,&v0,dim*dim,&J,dim*dim,&invJ);CHKERRQ(ierr); 988 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 989 for (c = cStart; c < cEnd; ++c) { 990 PetscScalar *x = NULL; 991 992 ierr = DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, invJ, &detJ);CHKERRQ(ierr); 993 if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ, c); 994 ierr = DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr); 995 996 for (field = 0, fieldOffset = 0; field < numFields; ++field) { 997 PetscObject obj; 998 PetscClassId id; 999 void * const ctx = ctxs ? ctxs[field] : NULL; 1000 PetscInt Nb, Nc, q, fc; 1001 1002 PetscReal elemDiff = 0.0; 1003 1004 ierr = DMGetField(dm, field, &obj);CHKERRQ(ierr); 1005 ierr = PetscObjectGetClassId(obj, &id);CHKERRQ(ierr); 1006 if (id == PETSCFE_CLASSID) {ierr = PetscFEGetNumComponents((PetscFE) obj, &Nc);CHKERRQ(ierr);ierr = PetscFEGetDimension((PetscFE) obj, &Nb);CHKERRQ(ierr);} 1007 else if (id == PETSCFV_CLASSID) {ierr = PetscFVGetNumComponents((PetscFV) obj, &Nc);CHKERRQ(ierr);Nb = 1;} 1008 else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field); 1009 if (debug) { 1010 char title[1024]; 1011 ierr = PetscSNPrintf(title, 1023, "Solution for Field %d", field);CHKERRQ(ierr); 1012 ierr = DMPrintCellVector(c, title, Nb*Nc, &x[fieldOffset]);CHKERRQ(ierr); 1013 } 1014 for (q = 0; q < numQuadPoints; ++q) { 1015 CoordinatesRefToReal(dim, dim, v0, J, &quadPoints[q*dim], coords); 1016 (*funcs[field])(coords, funcVal, ctx); 1017 if (id == PETSCFE_CLASSID) {ierr = PetscFEInterpolate_Static((PetscFE) obj, &x[fieldOffset], q, interpolant);CHKERRQ(ierr);} 1018 else if (id == PETSCFV_CLASSID) {ierr = PetscFVInterpolate_Static((PetscFV) obj, &x[fieldOffset], q, interpolant);CHKERRQ(ierr);} 1019 else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Unknown discretization type for field %d", field); 1020 for (fc = 0; fc < Nc; ++fc) { 1021 if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, " elem %d field %d diff %g\n", c, field, PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc]))*quadWeights[q]*detJ);CHKERRQ(ierr);} 1022 elemDiff += PetscSqr(PetscRealPart(interpolant[fc] - funcVal[fc]))*quadWeights[q]*detJ; 1023 } 1024 } 1025 fieldOffset += Nb*Nc; 1026 localDiff[field] += elemDiff; 1027 } 1028 ierr = DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr); 1029 } 1030 ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr); 1031 ierr = MPI_Allreduce(localDiff, diff, numFields, MPIU_REAL, MPI_SUM, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr); 1032 for (field = 0; field < numFields; ++field) diff[field] = PetscSqrtReal(diff[field]); 1033 ierr = PetscFree7(localDiff,funcVal,interpolant,coords,v0,J,invJ);CHKERRQ(ierr); 1034 PetscFunctionReturn(0); 1035 } 1036 1037 #undef __FUNCT__ 1038 #define __FUNCT__ "DMPlexComputeIntegralFEM" 1039 /*@ 1040 DMPlexComputeIntegralFEM - Form the local integral F from the local input X using pointwise functions specified by the user 1041 1042 Input Parameters: 1043 + dm - The mesh 1044 . X - Local input vector 1045 - user - The user context 1046 1047 Output Parameter: 1048 . integral - Local integral for each field 1049 1050 Level: developer 1051 1052 .seealso: DMPlexComputeResidualFEM() 1053 @*/ 1054 PetscErrorCode DMPlexComputeIntegralFEM(DM dm, Vec X, PetscReal *integral, void *user) 1055 { 1056 DM_Plex *mesh = (DM_Plex *) dm->data; 1057 DM dmAux; 1058 Vec localX, A; 1059 PetscDS prob, probAux = NULL; 1060 PetscQuadrature q; 1061 PetscSection section, sectionAux; 1062 PetscFECellGeom *cgeom; 1063 PetscScalar *u, *a = NULL; 1064 PetscInt dim, Nf, f, numCells, cStart, cEnd, c; 1065 PetscInt totDim, totDimAux; 1066 PetscErrorCode ierr; 1067 1068 PetscFunctionBegin; 1069 /*ierr = PetscLogEventBegin(DMPLEX_IntegralFEM,dm,0,0,0);CHKERRQ(ierr);*/ 1070 ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr); 1071 ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr); 1072 ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr); 1073 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 1074 ierr = DMGetDefaultSection(dm, §ion);CHKERRQ(ierr); 1075 ierr = DMGetDS(dm, &prob);CHKERRQ(ierr); 1076 ierr = PetscDSGetTotalDimension(prob, &totDim);CHKERRQ(ierr); 1077 ierr = PetscSectionGetNumFields(section, &Nf);CHKERRQ(ierr); 1078 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 1079 numCells = cEnd - cStart; 1080 for (f = 0; f < Nf; ++f) {integral[f] = 0.0;} 1081 ierr = PetscObjectQuery((PetscObject) dm, "dmAux", (PetscObject *) &dmAux);CHKERRQ(ierr); 1082 ierr = PetscObjectQuery((PetscObject) dm, "A", (PetscObject *) &A);CHKERRQ(ierr); 1083 if (dmAux) { 1084 ierr = DMGetDefaultSection(dmAux, §ionAux);CHKERRQ(ierr); 1085 ierr = DMGetDS(dmAux, &probAux);CHKERRQ(ierr); 1086 ierr = PetscDSGetTotalDimension(probAux, &totDimAux);CHKERRQ(ierr); 1087 } 1088 ierr = DMPlexInsertBoundaryValues(dm, localX, 0.0, NULL, NULL, NULL);CHKERRQ(ierr); 1089 ierr = PetscMalloc2(numCells*totDim,&u,numCells,&cgeom);CHKERRQ(ierr); 1090 if (dmAux) {ierr = PetscMalloc1(numCells*totDimAux, &a);CHKERRQ(ierr);} 1091 for (c = cStart; c < cEnd; ++c) { 1092 PetscScalar *x = NULL; 1093 PetscInt i; 1094 1095 ierr = DMPlexComputeCellGeometryFEM(dm, c, NULL, cgeom[c].v0, cgeom[c].J, cgeom[c].invJ, &cgeom[c].detJ);CHKERRQ(ierr); 1096 if (cgeom[c].detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", cgeom[c].detJ, c); 1097 ierr = DMPlexVecGetClosure(dm, section, localX, c, NULL, &x);CHKERRQ(ierr); 1098 for (i = 0; i < totDim; ++i) u[c*totDim+i] = x[i]; 1099 ierr = DMPlexVecRestoreClosure(dm, section, localX, c, NULL, &x);CHKERRQ(ierr); 1100 if (dmAux) { 1101 ierr = DMPlexVecGetClosure(dmAux, sectionAux, A, c, NULL, &x);CHKERRQ(ierr); 1102 for (i = 0; i < totDimAux; ++i) a[c*totDimAux+i] = x[i]; 1103 ierr = DMPlexVecRestoreClosure(dmAux, sectionAux, A, c, NULL, &x);CHKERRQ(ierr); 1104 } 1105 } 1106 for (f = 0; f < Nf; ++f) { 1107 PetscFE fe; 1108 PetscInt numQuadPoints, Nb; 1109 /* Conforming batches */ 1110 PetscInt numChunks, numBatches, numBlocks, Ne, blockSize, batchSize; 1111 /* Remainder */ 1112 PetscInt Nr, offset; 1113 1114 ierr = PetscDSGetDiscretization(prob, f, (PetscObject *) &fe);CHKERRQ(ierr); 1115 ierr = PetscFEGetQuadrature(fe, &q);CHKERRQ(ierr); 1116 ierr = PetscFEGetDimension(fe, &Nb);CHKERRQ(ierr); 1117 ierr = PetscFEGetTileSizes(fe, NULL, &numBlocks, NULL, &numBatches);CHKERRQ(ierr); 1118 ierr = PetscQuadratureGetData(q, NULL, &numQuadPoints, NULL, NULL);CHKERRQ(ierr); 1119 blockSize = Nb*numQuadPoints; 1120 batchSize = numBlocks * blockSize; 1121 ierr = PetscFESetTileSizes(fe, blockSize, numBlocks, batchSize, numBatches);CHKERRQ(ierr); 1122 numChunks = numCells / (numBatches*batchSize); 1123 Ne = numChunks*numBatches*batchSize; 1124 Nr = numCells % (numBatches*batchSize); 1125 offset = numCells - Nr; 1126 ierr = PetscFEIntegrate(fe, prob, f, Ne, cgeom, u, probAux, a, integral);CHKERRQ(ierr); 1127 ierr = PetscFEIntegrate(fe, prob, f, Nr, &cgeom[offset], &u[offset*totDim], probAux, &a[offset*totDimAux], integral);CHKERRQ(ierr); 1128 } 1129 ierr = PetscFree2(u,cgeom);CHKERRQ(ierr); 1130 if (dmAux) {ierr = PetscFree(a);CHKERRQ(ierr);} 1131 if (mesh->printFEM) { 1132 ierr = PetscPrintf(PetscObjectComm((PetscObject) dm), "Local integral:");CHKERRQ(ierr); 1133 for (f = 0; f < Nf; ++f) {ierr = PetscPrintf(PetscObjectComm((PetscObject) dm), " %g", integral[f]);CHKERRQ(ierr);} 1134 ierr = PetscPrintf(PetscObjectComm((PetscObject) dm), "\n");CHKERRQ(ierr); 1135 } 1136 ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr); 1137 /* TODO: Allreduce for integral */ 1138 /*ierr = PetscLogEventEnd(DMPLEX_IntegralFEM,dm,0,0,0);CHKERRQ(ierr);*/ 1139 PetscFunctionReturn(0); 1140 } 1141 1142 #undef __FUNCT__ 1143 #define __FUNCT__ "DMPlexComputeInterpolatorFEM" 1144 /*@ 1145 DMPlexComputeInterpolatorFEM - Form the local portion of the interpolation matrix I from the coarse DM to the uniformly refined DM. 1146 1147 Input Parameters: 1148 + dmf - The fine mesh 1149 . dmc - The coarse mesh 1150 - user - The user context 1151 1152 Output Parameter: 1153 . In - The interpolation matrix 1154 1155 Note: 1156 The first member of the user context must be an FEMContext. 1157 1158 We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator, 1159 like a GPU, or vectorize on a multicore machine. 1160 1161 Level: developer 1162 1163 .seealso: DMPlexComputeJacobianFEM() 1164 @*/ 1165 PetscErrorCode DMPlexComputeInterpolatorFEM(DM dmc, DM dmf, Mat In, void *user) 1166 { 1167 DM_Plex *mesh = (DM_Plex *) dmc->data; 1168 const char *name = "Interpolator"; 1169 PetscDS prob; 1170 PetscFE *feRef; 1171 PetscSection fsection, fglobalSection; 1172 PetscSection csection, cglobalSection; 1173 PetscScalar *elemMat; 1174 PetscInt dim, Nf, f, fieldI, fieldJ, offsetI, offsetJ, cStart, cEnd, c; 1175 PetscInt cTotDim, rTotDim = 0; 1176 PetscErrorCode ierr; 1177 1178 PetscFunctionBegin; 1179 ierr = PetscLogEventBegin(DMPLEX_InterpolatorFEM,dmc,dmf,0,0);CHKERRQ(ierr); 1180 ierr = DMGetDimension(dmf, &dim);CHKERRQ(ierr); 1181 ierr = DMGetDefaultSection(dmf, &fsection);CHKERRQ(ierr); 1182 ierr = DMGetDefaultGlobalSection(dmf, &fglobalSection);CHKERRQ(ierr); 1183 ierr = DMGetDefaultSection(dmc, &csection);CHKERRQ(ierr); 1184 ierr = DMGetDefaultGlobalSection(dmc, &cglobalSection);CHKERRQ(ierr); 1185 ierr = PetscSectionGetNumFields(fsection, &Nf);CHKERRQ(ierr); 1186 ierr = DMPlexGetHeightStratum(dmc, 0, &cStart, &cEnd);CHKERRQ(ierr); 1187 ierr = DMGetDS(dmf, &prob);CHKERRQ(ierr); 1188 ierr = PetscMalloc1(Nf,&feRef);CHKERRQ(ierr); 1189 for (f = 0; f < Nf; ++f) { 1190 PetscFE fe; 1191 PetscInt rNb, Nc; 1192 1193 ierr = PetscDSGetDiscretization(prob, f, (PetscObject *) &fe);CHKERRQ(ierr); 1194 ierr = PetscFERefine(fe, &feRef[f]);CHKERRQ(ierr); 1195 ierr = PetscFEGetDimension(feRef[f], &rNb);CHKERRQ(ierr); 1196 ierr = PetscFEGetNumComponents(fe, &Nc);CHKERRQ(ierr); 1197 rTotDim += rNb*Nc; 1198 } 1199 ierr = PetscDSGetTotalDimension(prob, &cTotDim);CHKERRQ(ierr); 1200 ierr = PetscMalloc1(rTotDim*cTotDim,&elemMat);CHKERRQ(ierr); 1201 ierr = PetscMemzero(elemMat, rTotDim*cTotDim * sizeof(PetscScalar));CHKERRQ(ierr); 1202 for (fieldI = 0, offsetI = 0; fieldI < Nf; ++fieldI) { 1203 PetscDualSpace Qref; 1204 PetscQuadrature f; 1205 const PetscReal *qpoints, *qweights; 1206 PetscReal *points; 1207 PetscInt npoints = 0, Nc, Np, fpdim, i, k, p, d; 1208 1209 /* Compose points from all dual basis functionals */ 1210 ierr = PetscFEGetDualSpace(feRef[fieldI], &Qref);CHKERRQ(ierr); 1211 ierr = PetscFEGetNumComponents(feRef[fieldI], &Nc);CHKERRQ(ierr); 1212 ierr = PetscDualSpaceGetDimension(Qref, &fpdim);CHKERRQ(ierr); 1213 for (i = 0; i < fpdim; ++i) { 1214 ierr = PetscDualSpaceGetFunctional(Qref, i, &f);CHKERRQ(ierr); 1215 ierr = PetscQuadratureGetData(f, NULL, &Np, NULL, NULL);CHKERRQ(ierr); 1216 npoints += Np; 1217 } 1218 ierr = PetscMalloc1(npoints*dim,&points);CHKERRQ(ierr); 1219 for (i = 0, k = 0; i < fpdim; ++i) { 1220 ierr = PetscDualSpaceGetFunctional(Qref, i, &f);CHKERRQ(ierr); 1221 ierr = PetscQuadratureGetData(f, NULL, &Np, &qpoints, NULL);CHKERRQ(ierr); 1222 for (p = 0; p < Np; ++p, ++k) for (d = 0; d < dim; ++d) points[k*dim+d] = qpoints[p*dim+d]; 1223 } 1224 1225 for (fieldJ = 0, offsetJ = 0; fieldJ < Nf; ++fieldJ) { 1226 PetscFE fe; 1227 PetscReal *B; 1228 PetscInt NcJ, cpdim, j; 1229 1230 /* Evaluate basis at points */ 1231 ierr = PetscDSGetDiscretization(prob, fieldJ, (PetscObject *) &fe);CHKERRQ(ierr); 1232 ierr = PetscFEGetNumComponents(fe, &NcJ);CHKERRQ(ierr); 1233 ierr = PetscFEGetDimension(fe, &cpdim);CHKERRQ(ierr); 1234 /* For now, fields only interpolate themselves */ 1235 if (fieldI == fieldJ) { 1236 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); 1237 ierr = PetscFEGetTabulation(fe, npoints, points, &B, NULL, NULL);CHKERRQ(ierr); 1238 for (i = 0, k = 0; i < fpdim; ++i) { 1239 ierr = PetscDualSpaceGetFunctional(Qref, i, &f);CHKERRQ(ierr); 1240 ierr = PetscQuadratureGetData(f, NULL, &Np, NULL, &qweights);CHKERRQ(ierr); 1241 for (p = 0; p < Np; ++p, ++k) { 1242 for (j = 0; j < cpdim; ++j) { 1243 for (c = 0; c < Nc; ++c) elemMat[(offsetI + i*Nc + c)*cTotDim + offsetJ + j*NcJ + c] += B[k*cpdim*NcJ+j*Nc+c]*qweights[p]; 1244 } 1245 } 1246 } 1247 ierr = PetscFERestoreTabulation(fe, npoints, points, &B, NULL, NULL);CHKERRQ(ierr);CHKERRQ(ierr); 1248 } 1249 offsetJ += cpdim*NcJ; 1250 } 1251 offsetI += fpdim*Nc; 1252 ierr = PetscFree(points);CHKERRQ(ierr); 1253 } 1254 if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(0, name, rTotDim, cTotDim, elemMat);CHKERRQ(ierr);} 1255 /* Preallocate matrix */ 1256 { 1257 PetscHashJK ht; 1258 PetscLayout rLayout; 1259 PetscInt *dnz, *onz, *cellCIndices, *cellFIndices; 1260 PetscInt locRows, rStart, rEnd, cell, r; 1261 1262 ierr = MatGetLocalSize(In, &locRows, NULL);CHKERRQ(ierr); 1263 ierr = PetscLayoutCreate(PetscObjectComm((PetscObject) In), &rLayout);CHKERRQ(ierr); 1264 ierr = PetscLayoutSetLocalSize(rLayout, locRows);CHKERRQ(ierr); 1265 ierr = PetscLayoutSetBlockSize(rLayout, 1);CHKERRQ(ierr); 1266 ierr = PetscLayoutSetUp(rLayout);CHKERRQ(ierr); 1267 ierr = PetscLayoutGetRange(rLayout, &rStart, &rEnd);CHKERRQ(ierr); 1268 ierr = PetscLayoutDestroy(&rLayout);CHKERRQ(ierr); 1269 ierr = PetscCalloc4(locRows,&dnz,locRows,&onz,cTotDim,&cellCIndices,rTotDim,&cellFIndices);CHKERRQ(ierr); 1270 ierr = PetscHashJKCreate(&ht);CHKERRQ(ierr); 1271 for (cell = cStart; cell < cEnd; ++cell) { 1272 ierr = DMPlexMatGetClosureIndicesRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, cell, cellCIndices, cellFIndices);CHKERRQ(ierr); 1273 for (r = 0; r < rTotDim; ++r) { 1274 PetscHashJKKey key; 1275 PetscHashJKIter missing, iter; 1276 1277 key.j = cellFIndices[r]; 1278 if (key.j < 0) continue; 1279 for (c = 0; c < cTotDim; ++c) { 1280 key.k = cellCIndices[c]; 1281 if (key.k < 0) continue; 1282 ierr = PetscHashJKPut(ht, key, &missing, &iter);CHKERRQ(ierr); 1283 if (missing) { 1284 ierr = PetscHashJKSet(ht, iter, 1);CHKERRQ(ierr); 1285 if ((key.k >= rStart) && (key.k < rEnd)) ++dnz[key.j-rStart]; 1286 else ++onz[key.j-rStart]; 1287 } 1288 } 1289 } 1290 } 1291 ierr = PetscHashJKDestroy(&ht);CHKERRQ(ierr); 1292 ierr = MatXAIJSetPreallocation(In, 1, dnz, onz, NULL, NULL);CHKERRQ(ierr); 1293 ierr = MatSetOption(In, MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr); 1294 ierr = PetscFree4(dnz,onz,cellCIndices,cellFIndices);CHKERRQ(ierr); 1295 } 1296 /* Fill matrix */ 1297 ierr = MatZeroEntries(In);CHKERRQ(ierr); 1298 for (c = cStart; c < cEnd; ++c) { 1299 ierr = DMPlexMatSetClosureRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, In, c, elemMat, INSERT_VALUES);CHKERRQ(ierr); 1300 } 1301 for (f = 0; f < Nf; ++f) {ierr = PetscFEDestroy(&feRef[f]);CHKERRQ(ierr);} 1302 ierr = PetscFree(feRef);CHKERRQ(ierr); 1303 ierr = PetscFree(elemMat);CHKERRQ(ierr); 1304 ierr = MatAssemblyBegin(In, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 1305 ierr = MatAssemblyEnd(In, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 1306 if (mesh->printFEM) { 1307 ierr = PetscPrintf(PETSC_COMM_WORLD, "%s:\n", name);CHKERRQ(ierr); 1308 ierr = MatChop(In, 1.0e-10);CHKERRQ(ierr); 1309 ierr = MatView(In, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr); 1310 } 1311 ierr = PetscLogEventEnd(DMPLEX_InterpolatorFEM,dmc,dmf,0,0);CHKERRQ(ierr); 1312 PetscFunctionReturn(0); 1313 } 1314 1315 #undef __FUNCT__ 1316 #define __FUNCT__ "DMPlexComputeInjectorFEM" 1317 PetscErrorCode DMPlexComputeInjectorFEM(DM dmc, DM dmf, VecScatter *sc, void *user) 1318 { 1319 PetscDS prob; 1320 PetscFE *feRef; 1321 Vec fv, cv; 1322 IS fis, cis; 1323 PetscSection fsection, fglobalSection, csection, cglobalSection; 1324 PetscInt *cmap, *cellCIndices, *cellFIndices, *cindices, *findices; 1325 PetscInt cTotDim, fTotDim = 0, Nf, f, field, cStart, cEnd, c, dim, d, startC, offsetC, offsetF, m; 1326 PetscErrorCode ierr; 1327 1328 PetscFunctionBegin; 1329 ierr = PetscLogEventBegin(DMPLEX_InjectorFEM,dmc,dmf,0,0);CHKERRQ(ierr); 1330 ierr = DMGetDimension(dmf, &dim);CHKERRQ(ierr); 1331 ierr = DMGetDefaultSection(dmf, &fsection);CHKERRQ(ierr); 1332 ierr = DMGetDefaultGlobalSection(dmf, &fglobalSection);CHKERRQ(ierr); 1333 ierr = DMGetDefaultSection(dmc, &csection);CHKERRQ(ierr); 1334 ierr = DMGetDefaultGlobalSection(dmc, &cglobalSection);CHKERRQ(ierr); 1335 ierr = PetscSectionGetNumFields(fsection, &Nf);CHKERRQ(ierr); 1336 ierr = DMPlexGetHeightStratum(dmc, 0, &cStart, &cEnd);CHKERRQ(ierr); 1337 ierr = DMGetDS(dmc, &prob);CHKERRQ(ierr); 1338 ierr = PetscMalloc1(Nf,&feRef);CHKERRQ(ierr); 1339 for (f = 0; f < Nf; ++f) { 1340 PetscFE fe; 1341 PetscInt fNb, Nc; 1342 1343 ierr = PetscDSGetDiscretization(prob, f, (PetscObject *) &fe);CHKERRQ(ierr); 1344 ierr = PetscFERefine(fe, &feRef[f]);CHKERRQ(ierr); 1345 ierr = PetscFEGetDimension(feRef[f], &fNb);CHKERRQ(ierr); 1346 ierr = PetscFEGetNumComponents(fe, &Nc);CHKERRQ(ierr); 1347 fTotDim += fNb*Nc; 1348 } 1349 ierr = PetscDSGetTotalDimension(prob, &cTotDim);CHKERRQ(ierr); 1350 ierr = PetscMalloc1(cTotDim,&cmap);CHKERRQ(ierr); 1351 for (field = 0, offsetC = 0, offsetF = 0; field < Nf; ++field) { 1352 PetscFE feC; 1353 PetscDualSpace QF, QC; 1354 PetscInt NcF, NcC, fpdim, cpdim; 1355 1356 ierr = PetscDSGetDiscretization(prob, field, (PetscObject *) &feC);CHKERRQ(ierr); 1357 ierr = PetscFEGetNumComponents(feC, &NcC);CHKERRQ(ierr); 1358 ierr = PetscFEGetNumComponents(feRef[field], &NcF);CHKERRQ(ierr); 1359 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); 1360 ierr = PetscFEGetDualSpace(feRef[field], &QF);CHKERRQ(ierr); 1361 ierr = PetscDualSpaceGetDimension(QF, &fpdim);CHKERRQ(ierr); 1362 ierr = PetscFEGetDualSpace(feC, &QC);CHKERRQ(ierr); 1363 ierr = PetscDualSpaceGetDimension(QC, &cpdim);CHKERRQ(ierr); 1364 for (c = 0; c < cpdim; ++c) { 1365 PetscQuadrature cfunc; 1366 const PetscReal *cqpoints; 1367 PetscInt NpC; 1368 1369 ierr = PetscDualSpaceGetFunctional(QC, c, &cfunc);CHKERRQ(ierr); 1370 ierr = PetscQuadratureGetData(cfunc, NULL, &NpC, &cqpoints, NULL);CHKERRQ(ierr); 1371 if (NpC != 1) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Do not know how to do injection for moments"); 1372 for (f = 0; f < fpdim; ++f) { 1373 PetscQuadrature ffunc; 1374 const PetscReal *fqpoints; 1375 PetscReal sum = 0.0; 1376 PetscInt NpF, comp; 1377 1378 ierr = PetscDualSpaceGetFunctional(QF, f, &ffunc);CHKERRQ(ierr); 1379 ierr = PetscQuadratureGetData(ffunc, NULL, &NpF, &fqpoints, NULL);CHKERRQ(ierr); 1380 if (NpC != NpF) continue; 1381 for (d = 0; d < dim; ++d) sum += PetscAbsReal(cqpoints[d] - fqpoints[d]); 1382 if (sum > 1.0e-9) continue; 1383 for (comp = 0; comp < NcC; ++comp) { 1384 cmap[(offsetC+c)*NcC+comp] = (offsetF+f)*NcF+comp; 1385 } 1386 break; 1387 } 1388 } 1389 offsetC += cpdim*NcC; 1390 offsetF += fpdim*NcF; 1391 } 1392 for (f = 0; f < Nf; ++f) {ierr = PetscFEDestroy(&feRef[f]);CHKERRQ(ierr);} 1393 ierr = PetscFree(feRef);CHKERRQ(ierr); 1394 1395 ierr = DMGetGlobalVector(dmf, &fv);CHKERRQ(ierr); 1396 ierr = DMGetGlobalVector(dmc, &cv);CHKERRQ(ierr); 1397 ierr = VecGetOwnershipRange(cv, &startC, NULL);CHKERRQ(ierr); 1398 ierr = PetscSectionGetConstrainedStorageSize(cglobalSection, &m);CHKERRQ(ierr); 1399 ierr = PetscMalloc2(cTotDim,&cellCIndices,fTotDim,&cellFIndices);CHKERRQ(ierr); 1400 ierr = PetscMalloc1(m,&cindices);CHKERRQ(ierr); 1401 ierr = PetscMalloc1(m,&findices);CHKERRQ(ierr); 1402 for (d = 0; d < m; ++d) cindices[d] = findices[d] = -1; 1403 for (c = cStart; c < cEnd; ++c) { 1404 ierr = DMPlexMatGetClosureIndicesRefined(dmf, fsection, fglobalSection, dmc, csection, cglobalSection, c, cellCIndices, cellFIndices);CHKERRQ(ierr); 1405 for (d = 0; d < cTotDim; ++d) { 1406 if (cellCIndices[d] < 0) continue; 1407 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]]); 1408 cindices[cellCIndices[d]-startC] = cellCIndices[d]; 1409 findices[cellCIndices[d]-startC] = cellFIndices[cmap[d]]; 1410 } 1411 } 1412 ierr = PetscFree(cmap);CHKERRQ(ierr); 1413 ierr = PetscFree2(cellCIndices,cellFIndices);CHKERRQ(ierr); 1414 1415 ierr = ISCreateGeneral(PETSC_COMM_SELF, m, cindices, PETSC_OWN_POINTER, &cis);CHKERRQ(ierr); 1416 ierr = ISCreateGeneral(PETSC_COMM_SELF, m, findices, PETSC_OWN_POINTER, &fis);CHKERRQ(ierr); 1417 ierr = VecScatterCreate(cv, cis, fv, fis, sc);CHKERRQ(ierr); 1418 ierr = ISDestroy(&cis);CHKERRQ(ierr); 1419 ierr = ISDestroy(&fis);CHKERRQ(ierr); 1420 ierr = DMRestoreGlobalVector(dmf, &fv);CHKERRQ(ierr); 1421 ierr = DMRestoreGlobalVector(dmc, &cv);CHKERRQ(ierr); 1422 ierr = PetscLogEventEnd(DMPLEX_InjectorFEM,dmc,dmf,0,0);CHKERRQ(ierr); 1423 PetscFunctionReturn(0); 1424 } 1425