1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 #include <petsc/private/snesimpl.h> /*I "petscsnes.h" I*/ 3 #include <petscds.h> 4 #include <petsc/private/petscimpl.h> 5 #include <petsc/private/petscfeimpl.h> 6 7 static void pressure_Private(PetscInt dim, PetscInt Nf, PetscInt NfAux, 8 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 9 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 10 PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar p[]) 11 { 12 p[0] = u[uOff[1]]; 13 } 14 15 /* 16 SNESCorrectDiscretePressure_Private - Add a vector in the nullspace to make the continuum integral of the pressure field equal to zero. This is normally used only to evaluate convergence rates for the pressure accurately. 17 18 Collective on SNES 19 20 Input Parameters: 21 + snes - The SNES 22 . pfield - The field number for pressure 23 . nullspace - The pressure nullspace 24 . u - The solution vector 25 - ctx - An optional user context 26 27 Output Parameter: 28 . u - The solution with a continuum pressure integral of zero 29 30 Notes: 31 If int(u) = a and int(n) = b, then int(u - a/b n) = a - a/b b = 0. We assume that the nullspace is a single vector given explicitly. 32 33 Level: developer 34 35 .seealso: SNESConvergedCorrectPressure() 36 */ 37 static PetscErrorCode SNESCorrectDiscretePressure_Private(SNES snes, PetscInt pfield, MatNullSpace nullspace, Vec u, void *ctx) 38 { 39 DM dm; 40 PetscDS ds; 41 const Vec *nullvecs; 42 PetscScalar pintd, *intc, *intn; 43 MPI_Comm comm; 44 PetscInt Nf, Nv; 45 46 PetscFunctionBegin; 47 CHKERRQ(PetscObjectGetComm((PetscObject) snes, &comm)); 48 CHKERRQ(SNESGetDM(snes, &dm)); 49 PetscCheckFalse(!dm,comm, PETSC_ERR_ARG_WRONG, "Cannot compute test without a SNES DM"); 50 PetscCheckFalse(!nullspace,comm, PETSC_ERR_ARG_WRONG, "Cannot compute test without a Jacobian nullspace"); 51 CHKERRQ(DMGetDS(dm, &ds)); 52 CHKERRQ(PetscDSSetObjective(ds, pfield, pressure_Private)); 53 CHKERRQ(MatNullSpaceGetVecs(nullspace, NULL, &Nv, &nullvecs)); 54 PetscCheckFalse(Nv != 1,comm, PETSC_ERR_ARG_OUTOFRANGE, "Can only handle a single null vector for pressure, not %D", Nv); 55 CHKERRQ(VecDot(nullvecs[0], u, &pintd)); 56 PetscCheckFalse(PetscAbsScalar(pintd) > PETSC_SMALL,comm, PETSC_ERR_ARG_WRONG, "Discrete integral of pressure: %g", (double) PetscRealPart(pintd)); 57 CHKERRQ(PetscDSGetNumFields(ds, &Nf)); 58 CHKERRQ(PetscMalloc2(Nf, &intc, Nf, &intn)); 59 CHKERRQ(DMPlexComputeIntegralFEM(dm, nullvecs[0], intn, ctx)); 60 CHKERRQ(DMPlexComputeIntegralFEM(dm, u, intc, ctx)); 61 CHKERRQ(VecAXPY(u, -intc[pfield]/intn[pfield], nullvecs[0])); 62 #if defined (PETSC_USE_DEBUG) 63 CHKERRQ(DMPlexComputeIntegralFEM(dm, u, intc, ctx)); 64 PetscCheckFalse(PetscAbsScalar(intc[pfield]) > PETSC_SMALL,comm, PETSC_ERR_ARG_WRONG, "Continuum integral of pressure after correction: %g", (double) PetscRealPart(intc[pfield])); 65 #endif 66 CHKERRQ(PetscFree2(intc, intn)); 67 PetscFunctionReturn(0); 68 } 69 70 /*@C 71 SNESConvergedCorrectPressure - Convergence test that adds a vector in the nullspace to make the continuum integral of the pressure field equal to zero. This is normally used only to evaluate convergence rates for the pressure accurately. The convergence test itself just mimics SNESConvergedDefault(). 72 73 Logically Collective on SNES 74 75 Input Parameters: 76 + snes - the SNES context 77 . it - the iteration (0 indicates before any Newton steps) 78 . xnorm - 2-norm of current iterate 79 . snorm - 2-norm of current step 80 . fnorm - 2-norm of function at current iterate 81 - ctx - Optional user context 82 83 Output Parameter: 84 . reason - SNES_CONVERGED_ITERATING, SNES_CONVERGED_ITS, or SNES_DIVERGED_FNORM_NAN 85 86 Notes: 87 In order to use this monitor, you must setup several PETSc structures. First fields must be added to the DM, and a PetscDS must be created with discretizations of those fields. We currently assume that the pressure field has index 1. The pressure field must have a nullspace, likely created using the DMSetNullSpaceConstructor() interface. Last we must be able to integrate the pressure over the domain, so the DM attached to the SNES must be a Plex at this time. 88 89 Level: advanced 90 91 .seealso: SNESConvergedDefault(), SNESSetConvergenceTest(), DMSetNullSpaceConstructor() 92 @*/ 93 PetscErrorCode SNESConvergedCorrectPressure(SNES snes, PetscInt it, PetscReal xnorm, PetscReal gnorm, PetscReal f, SNESConvergedReason *reason, void *ctx) 94 { 95 PetscBool monitorIntegral = PETSC_FALSE; 96 97 PetscFunctionBegin; 98 CHKERRQ(SNESConvergedDefault(snes, it, xnorm, gnorm, f, reason, ctx)); 99 if (monitorIntegral) { 100 Mat J; 101 Vec u; 102 MatNullSpace nullspace; 103 const Vec *nullvecs; 104 PetscScalar pintd; 105 106 CHKERRQ(SNESGetSolution(snes, &u)); 107 CHKERRQ(SNESGetJacobian(snes, &J, NULL, NULL, NULL)); 108 CHKERRQ(MatGetNullSpace(J, &nullspace)); 109 CHKERRQ(MatNullSpaceGetVecs(nullspace, NULL, NULL, &nullvecs)); 110 CHKERRQ(VecDot(nullvecs[0], u, &pintd)); 111 CHKERRQ(PetscInfo(snes, "SNES: Discrete integral of pressure: %g\n", (double) PetscRealPart(pintd))); 112 } 113 if (*reason > 0) { 114 Mat J; 115 Vec u; 116 MatNullSpace nullspace; 117 PetscInt pfield = 1; 118 119 CHKERRQ(SNESGetSolution(snes, &u)); 120 CHKERRQ(SNESGetJacobian(snes, &J, NULL, NULL, NULL)); 121 CHKERRQ(MatGetNullSpace(J, &nullspace)); 122 CHKERRQ(SNESCorrectDiscretePressure_Private(snes, pfield, nullspace, u, ctx)); 123 } 124 PetscFunctionReturn(0); 125 } 126 127 /************************** Interpolation *******************************/ 128 129 static PetscErrorCode DMSNESConvertPlex(DM dm, DM *plex, PetscBool copy) 130 { 131 PetscBool isPlex; 132 133 PetscFunctionBegin; 134 CHKERRQ(PetscObjectTypeCompare((PetscObject) dm, DMPLEX, &isPlex)); 135 if (isPlex) { 136 *plex = dm; 137 CHKERRQ(PetscObjectReference((PetscObject) dm)); 138 } else { 139 CHKERRQ(PetscObjectQuery((PetscObject) dm, "dm_plex", (PetscObject *) plex)); 140 if (!*plex) { 141 CHKERRQ(DMConvert(dm,DMPLEX,plex)); 142 CHKERRQ(PetscObjectCompose((PetscObject) dm, "dm_plex", (PetscObject) *plex)); 143 if (copy) { 144 CHKERRQ(DMCopyDMSNES(dm, *plex)); 145 CHKERRQ(DMCopyAuxiliaryVec(dm, *plex)); 146 } 147 } else { 148 CHKERRQ(PetscObjectReference((PetscObject) *plex)); 149 } 150 } 151 PetscFunctionReturn(0); 152 } 153 154 /*@C 155 DMInterpolationCreate - Creates a DMInterpolationInfo context 156 157 Collective 158 159 Input Parameter: 160 . comm - the communicator 161 162 Output Parameter: 163 . ctx - the context 164 165 Level: beginner 166 167 .seealso: DMInterpolationEvaluate(), DMInterpolationAddPoints(), DMInterpolationDestroy() 168 @*/ 169 PetscErrorCode DMInterpolationCreate(MPI_Comm comm, DMInterpolationInfo *ctx) 170 { 171 PetscFunctionBegin; 172 PetscValidPointer(ctx, 2); 173 CHKERRQ(PetscNew(ctx)); 174 175 (*ctx)->comm = comm; 176 (*ctx)->dim = -1; 177 (*ctx)->nInput = 0; 178 (*ctx)->points = NULL; 179 (*ctx)->cells = NULL; 180 (*ctx)->n = -1; 181 (*ctx)->coords = NULL; 182 PetscFunctionReturn(0); 183 } 184 185 /*@C 186 DMInterpolationSetDim - Sets the spatial dimension for the interpolation context 187 188 Not collective 189 190 Input Parameters: 191 + ctx - the context 192 - dim - the spatial dimension 193 194 Level: intermediate 195 196 .seealso: DMInterpolationGetDim(), DMInterpolationEvaluate(), DMInterpolationAddPoints() 197 @*/ 198 PetscErrorCode DMInterpolationSetDim(DMInterpolationInfo ctx, PetscInt dim) 199 { 200 PetscFunctionBegin; 201 PetscCheckFalse((dim < 1) || (dim > 3),ctx->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension for points: %D", dim); 202 ctx->dim = dim; 203 PetscFunctionReturn(0); 204 } 205 206 /*@C 207 DMInterpolationGetDim - Gets the spatial dimension for the interpolation context 208 209 Not collective 210 211 Input Parameter: 212 . ctx - the context 213 214 Output Parameter: 215 . dim - the spatial dimension 216 217 Level: intermediate 218 219 .seealso: DMInterpolationSetDim(), DMInterpolationEvaluate(), DMInterpolationAddPoints() 220 @*/ 221 PetscErrorCode DMInterpolationGetDim(DMInterpolationInfo ctx, PetscInt *dim) 222 { 223 PetscFunctionBegin; 224 PetscValidIntPointer(dim, 2); 225 *dim = ctx->dim; 226 PetscFunctionReturn(0); 227 } 228 229 /*@C 230 DMInterpolationSetDof - Sets the number of fields interpolated at a point for the interpolation context 231 232 Not collective 233 234 Input Parameters: 235 + ctx - the context 236 - dof - the number of fields 237 238 Level: intermediate 239 240 .seealso: DMInterpolationGetDof(), DMInterpolationEvaluate(), DMInterpolationAddPoints() 241 @*/ 242 PetscErrorCode DMInterpolationSetDof(DMInterpolationInfo ctx, PetscInt dof) 243 { 244 PetscFunctionBegin; 245 PetscCheckFalse(dof < 1,ctx->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of components: %D", dof); 246 ctx->dof = dof; 247 PetscFunctionReturn(0); 248 } 249 250 /*@C 251 DMInterpolationGetDof - Gets the number of fields interpolated at a point for the interpolation context 252 253 Not collective 254 255 Input Parameter: 256 . ctx - the context 257 258 Output Parameter: 259 . dof - the number of fields 260 261 Level: intermediate 262 263 .seealso: DMInterpolationSetDof(), DMInterpolationEvaluate(), DMInterpolationAddPoints() 264 @*/ 265 PetscErrorCode DMInterpolationGetDof(DMInterpolationInfo ctx, PetscInt *dof) 266 { 267 PetscFunctionBegin; 268 PetscValidIntPointer(dof, 2); 269 *dof = ctx->dof; 270 PetscFunctionReturn(0); 271 } 272 273 /*@C 274 DMInterpolationAddPoints - Add points at which we will interpolate the fields 275 276 Not collective 277 278 Input Parameters: 279 + ctx - the context 280 . n - the number of points 281 - points - the coordinates for each point, an array of size n * dim 282 283 Note: The coordinate information is copied. 284 285 Level: intermediate 286 287 .seealso: DMInterpolationSetDim(), DMInterpolationEvaluate(), DMInterpolationCreate() 288 @*/ 289 PetscErrorCode DMInterpolationAddPoints(DMInterpolationInfo ctx, PetscInt n, PetscReal points[]) 290 { 291 PetscFunctionBegin; 292 PetscCheckFalse(ctx->dim < 0,ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "The spatial dimension has not been set"); 293 PetscCheckFalse(ctx->points,ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "Cannot add points multiple times yet"); 294 ctx->nInput = n; 295 296 CHKERRQ(PetscMalloc1(n*ctx->dim, &ctx->points)); 297 CHKERRQ(PetscArraycpy(ctx->points, points, n*ctx->dim)); 298 PetscFunctionReturn(0); 299 } 300 301 /*@C 302 DMInterpolationSetUp - Compute spatial indices for point location during interpolation 303 304 Collective on ctx 305 306 Input Parameters: 307 + ctx - the context 308 . dm - the DM for the function space used for interpolation 309 . redundantPoints - If PETSC_TRUE, all processes are passing in the same array of points. Otherwise, points need to be communicated among processes. 310 - ignoreOutsideDomain - If PETSC_TRUE, ignore points outside the domain, otherwise return an error 311 312 Level: intermediate 313 314 .seealso: DMInterpolationEvaluate(), DMInterpolationAddPoints(), DMInterpolationCreate() 315 @*/ 316 PetscErrorCode DMInterpolationSetUp(DMInterpolationInfo ctx, DM dm, PetscBool redundantPoints, PetscBool ignoreOutsideDomain) 317 { 318 MPI_Comm comm = ctx->comm; 319 PetscScalar *a; 320 PetscInt p, q, i; 321 PetscMPIInt rank, size; 322 Vec pointVec; 323 PetscSF cellSF; 324 PetscLayout layout; 325 PetscReal *globalPoints; 326 PetscScalar *globalPointsScalar; 327 const PetscInt *ranges; 328 PetscMPIInt *counts, *displs; 329 const PetscSFNode *foundCells; 330 const PetscInt *foundPoints; 331 PetscMPIInt *foundProcs, *globalProcs; 332 PetscInt n, N, numFound; 333 334 PetscFunctionBegin; 335 PetscValidHeaderSpecific(dm, DM_CLASSID, 2); 336 CHKERRMPI(MPI_Comm_size(comm, &size)); 337 CHKERRMPI(MPI_Comm_rank(comm, &rank)); 338 PetscCheckFalse(ctx->dim < 0,comm, PETSC_ERR_ARG_WRONGSTATE, "The spatial dimension has not been set"); 339 /* Locate points */ 340 n = ctx->nInput; 341 if (!redundantPoints) { 342 CHKERRQ(PetscLayoutCreate(comm, &layout)); 343 CHKERRQ(PetscLayoutSetBlockSize(layout, 1)); 344 CHKERRQ(PetscLayoutSetLocalSize(layout, n)); 345 CHKERRQ(PetscLayoutSetUp(layout)); 346 CHKERRQ(PetscLayoutGetSize(layout, &N)); 347 /* Communicate all points to all processes */ 348 CHKERRQ(PetscMalloc3(N*ctx->dim,&globalPoints,size,&counts,size,&displs)); 349 CHKERRQ(PetscLayoutGetRanges(layout, &ranges)); 350 for (p = 0; p < size; ++p) { 351 counts[p] = (ranges[p+1] - ranges[p])*ctx->dim; 352 displs[p] = ranges[p]*ctx->dim; 353 } 354 CHKERRMPI(MPI_Allgatherv(ctx->points, n*ctx->dim, MPIU_REAL, globalPoints, counts, displs, MPIU_REAL, comm)); 355 } else { 356 N = n; 357 globalPoints = ctx->points; 358 counts = displs = NULL; 359 layout = NULL; 360 } 361 #if 0 362 CHKERRQ(PetscMalloc3(N,&foundCells,N,&foundProcs,N,&globalProcs)); 363 /* foundCells[p] = m->locatePoint(&globalPoints[p*ctx->dim]); */ 364 #else 365 #if defined(PETSC_USE_COMPLEX) 366 CHKERRQ(PetscMalloc1(N*ctx->dim,&globalPointsScalar)); 367 for (i=0; i<N*ctx->dim; i++) globalPointsScalar[i] = globalPoints[i]; 368 #else 369 globalPointsScalar = globalPoints; 370 #endif 371 CHKERRQ(VecCreateSeqWithArray(PETSC_COMM_SELF, ctx->dim, N*ctx->dim, globalPointsScalar, &pointVec)); 372 CHKERRQ(PetscMalloc2(N,&foundProcs,N,&globalProcs)); 373 for (p = 0; p < N; ++p) {foundProcs[p] = size;} 374 cellSF = NULL; 375 CHKERRQ(DMLocatePoints(dm, pointVec, DM_POINTLOCATION_REMOVE, &cellSF)); 376 CHKERRQ(PetscSFGetGraph(cellSF,NULL,&numFound,&foundPoints,&foundCells)); 377 #endif 378 for (p = 0; p < numFound; ++p) { 379 if (foundCells[p].index >= 0) foundProcs[foundPoints ? foundPoints[p] : p] = rank; 380 } 381 /* Let the lowest rank process own each point */ 382 CHKERRMPI(MPIU_Allreduce(foundProcs, globalProcs, N, MPI_INT, MPI_MIN, comm)); 383 ctx->n = 0; 384 for (p = 0; p < N; ++p) { 385 if (globalProcs[p] == size) { 386 PetscCheckFalse(!ignoreOutsideDomain,comm, PETSC_ERR_PLIB, "Point %d: %g %g %g not located in mesh", p, (double)globalPoints[p*ctx->dim+0], (double)(ctx->dim > 1 ? globalPoints[p*ctx->dim+1] : 0.0), (double)(ctx->dim > 2 ? globalPoints[p*ctx->dim+2] : 0.0)); 387 else if (rank == 0) ++ctx->n; 388 } else if (globalProcs[p] == rank) ++ctx->n; 389 } 390 /* Create coordinates vector and array of owned cells */ 391 CHKERRQ(PetscMalloc1(ctx->n, &ctx->cells)); 392 CHKERRQ(VecCreate(comm, &ctx->coords)); 393 CHKERRQ(VecSetSizes(ctx->coords, ctx->n*ctx->dim, PETSC_DECIDE)); 394 CHKERRQ(VecSetBlockSize(ctx->coords, ctx->dim)); 395 CHKERRQ(VecSetType(ctx->coords,VECSTANDARD)); 396 CHKERRQ(VecGetArray(ctx->coords, &a)); 397 for (p = 0, q = 0, i = 0; p < N; ++p) { 398 if (globalProcs[p] == rank) { 399 PetscInt d; 400 401 for (d = 0; d < ctx->dim; ++d, ++i) a[i] = globalPoints[p*ctx->dim+d]; 402 ctx->cells[q] = foundCells[q].index; 403 ++q; 404 } 405 if (globalProcs[p] == size && rank == 0) { 406 PetscInt d; 407 408 for (d = 0; d < ctx->dim; ++d, ++i) a[i] = 0.; 409 ctx->cells[q] = -1; 410 ++q; 411 } 412 } 413 CHKERRQ(VecRestoreArray(ctx->coords, &a)); 414 #if 0 415 CHKERRQ(PetscFree3(foundCells,foundProcs,globalProcs)); 416 #else 417 CHKERRQ(PetscFree2(foundProcs,globalProcs)); 418 CHKERRQ(PetscSFDestroy(&cellSF)); 419 CHKERRQ(VecDestroy(&pointVec)); 420 #endif 421 if ((void*)globalPointsScalar != (void*)globalPoints) CHKERRQ(PetscFree(globalPointsScalar)); 422 if (!redundantPoints) CHKERRQ(PetscFree3(globalPoints,counts,displs)); 423 CHKERRQ(PetscLayoutDestroy(&layout)); 424 PetscFunctionReturn(0); 425 } 426 427 /*@C 428 DMInterpolationGetCoordinates - Gets a Vec with the coordinates of each interpolation point 429 430 Collective on ctx 431 432 Input Parameter: 433 . ctx - the context 434 435 Output Parameter: 436 . coordinates - the coordinates of interpolation points 437 438 Note: The local vector entries correspond to interpolation points lying on this process, according to the associated DM. This is a borrowed vector that the user should not destroy. 439 440 Level: intermediate 441 442 .seealso: DMInterpolationEvaluate(), DMInterpolationAddPoints(), DMInterpolationCreate() 443 @*/ 444 PetscErrorCode DMInterpolationGetCoordinates(DMInterpolationInfo ctx, Vec *coordinates) 445 { 446 PetscFunctionBegin; 447 PetscValidPointer(coordinates, 2); 448 PetscCheckFalse(!ctx->coords,ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "The interpolation context has not been setup."); 449 *coordinates = ctx->coords; 450 PetscFunctionReturn(0); 451 } 452 453 /*@C 454 DMInterpolationGetVector - Gets a Vec which can hold all the interpolated field values 455 456 Collective on ctx 457 458 Input Parameter: 459 . ctx - the context 460 461 Output Parameter: 462 . v - a vector capable of holding the interpolated field values 463 464 Note: This vector should be returned using DMInterpolationRestoreVector(). 465 466 Level: intermediate 467 468 .seealso: DMInterpolationRestoreVector(), DMInterpolationEvaluate(), DMInterpolationAddPoints(), DMInterpolationCreate() 469 @*/ 470 PetscErrorCode DMInterpolationGetVector(DMInterpolationInfo ctx, Vec *v) 471 { 472 PetscFunctionBegin; 473 PetscValidPointer(v, 2); 474 PetscCheckFalse(!ctx->coords,ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "The interpolation context has not been setup."); 475 CHKERRQ(VecCreate(ctx->comm, v)); 476 CHKERRQ(VecSetSizes(*v, ctx->n*ctx->dof, PETSC_DECIDE)); 477 CHKERRQ(VecSetBlockSize(*v, ctx->dof)); 478 CHKERRQ(VecSetType(*v,VECSTANDARD)); 479 PetscFunctionReturn(0); 480 } 481 482 /*@C 483 DMInterpolationRestoreVector - Returns a Vec which can hold all the interpolated field values 484 485 Collective on ctx 486 487 Input Parameters: 488 + ctx - the context 489 - v - a vector capable of holding the interpolated field values 490 491 Level: intermediate 492 493 .seealso: DMInterpolationGetVector(), DMInterpolationEvaluate(), DMInterpolationAddPoints(), DMInterpolationCreate() 494 @*/ 495 PetscErrorCode DMInterpolationRestoreVector(DMInterpolationInfo ctx, Vec *v) 496 { 497 PetscFunctionBegin; 498 PetscValidPointer(v, 2); 499 PetscCheckFalse(!ctx->coords,ctx->comm, PETSC_ERR_ARG_WRONGSTATE, "The interpolation context has not been setup."); 500 CHKERRQ(VecDestroy(v)); 501 PetscFunctionReturn(0); 502 } 503 504 static inline PetscErrorCode DMInterpolate_Segment_Private(DMInterpolationInfo ctx, DM dm, Vec xLocal, Vec v) 505 { 506 PetscReal v0, J, invJ, detJ; 507 const PetscInt dof = ctx->dof; 508 const PetscScalar *coords; 509 PetscScalar *a; 510 PetscInt p; 511 512 PetscFunctionBegin; 513 CHKERRQ(VecGetArrayRead(ctx->coords, &coords)); 514 CHKERRQ(VecGetArray(v, &a)); 515 for (p = 0; p < ctx->n; ++p) { 516 PetscInt c = ctx->cells[p]; 517 PetscScalar *x = NULL; 518 PetscReal xir[1]; 519 PetscInt xSize, comp; 520 521 CHKERRQ(DMPlexComputeCellGeometryFEM(dm, c, NULL, &v0, &J, &invJ, &detJ)); 522 PetscCheck(detJ > 0.0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %" PetscInt_FMT, (double) detJ, c); 523 xir[0] = invJ*PetscRealPart(coords[p] - v0); 524 CHKERRQ(DMPlexVecGetClosure(dm, NULL, xLocal, c, &xSize, &x)); 525 if (2*dof == xSize) { 526 for (comp = 0; comp < dof; ++comp) a[p*dof+comp] = x[0*dof+comp]*(1 - xir[0]) + x[1*dof+comp]*xir[0]; 527 } else if (dof == xSize) { 528 for (comp = 0; comp < dof; ++comp) a[p*dof+comp] = x[0*dof+comp]; 529 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Input closure size %" PetscInt_FMT " must be either %" PetscInt_FMT " or %" PetscInt_FMT, xSize, 2*dof, dof); 530 CHKERRQ(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, &xSize, &x)); 531 } 532 CHKERRQ(VecRestoreArray(v, &a)); 533 CHKERRQ(VecRestoreArrayRead(ctx->coords, &coords)); 534 PetscFunctionReturn(0); 535 } 536 537 static inline PetscErrorCode DMInterpolate_Triangle_Private(DMInterpolationInfo ctx, DM dm, Vec xLocal, Vec v) 538 { 539 PetscReal *v0, *J, *invJ, detJ; 540 const PetscScalar *coords; 541 PetscScalar *a; 542 PetscInt p; 543 544 PetscFunctionBegin; 545 CHKERRQ(PetscMalloc3(ctx->dim,&v0,ctx->dim*ctx->dim,&J,ctx->dim*ctx->dim,&invJ)); 546 CHKERRQ(VecGetArrayRead(ctx->coords, &coords)); 547 CHKERRQ(VecGetArray(v, &a)); 548 for (p = 0; p < ctx->n; ++p) { 549 PetscInt c = ctx->cells[p]; 550 PetscScalar *x = NULL; 551 PetscReal xi[4]; 552 PetscInt d, f, comp; 553 554 CHKERRQ(DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, invJ, &detJ)); 555 PetscCheckFalse(detJ <= 0.0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %D", (double)detJ, c); 556 CHKERRQ(DMPlexVecGetClosure(dm, NULL, xLocal, c, NULL, &x)); 557 for (comp = 0; comp < ctx->dof; ++comp) a[p*ctx->dof+comp] = x[0*ctx->dof+comp]; 558 559 for (d = 0; d < ctx->dim; ++d) { 560 xi[d] = 0.0; 561 for (f = 0; f < ctx->dim; ++f) xi[d] += invJ[d*ctx->dim+f]*0.5*PetscRealPart(coords[p*ctx->dim+f] - v0[f]); 562 for (comp = 0; comp < ctx->dof; ++comp) a[p*ctx->dof+comp] += PetscRealPart(x[(d+1)*ctx->dof+comp] - x[0*ctx->dof+comp])*xi[d]; 563 } 564 CHKERRQ(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, NULL, &x)); 565 } 566 CHKERRQ(VecRestoreArray(v, &a)); 567 CHKERRQ(VecRestoreArrayRead(ctx->coords, &coords)); 568 CHKERRQ(PetscFree3(v0, J, invJ)); 569 PetscFunctionReturn(0); 570 } 571 572 static inline PetscErrorCode DMInterpolate_Tetrahedron_Private(DMInterpolationInfo ctx, DM dm, Vec xLocal, Vec v) 573 { 574 PetscReal *v0, *J, *invJ, detJ; 575 const PetscScalar *coords; 576 PetscScalar *a; 577 PetscInt p; 578 579 PetscFunctionBegin; 580 CHKERRQ(PetscMalloc3(ctx->dim,&v0,ctx->dim*ctx->dim,&J,ctx->dim*ctx->dim,&invJ)); 581 CHKERRQ(VecGetArrayRead(ctx->coords, &coords)); 582 CHKERRQ(VecGetArray(v, &a)); 583 for (p = 0; p < ctx->n; ++p) { 584 PetscInt c = ctx->cells[p]; 585 const PetscInt order[3] = {2, 1, 3}; 586 PetscScalar *x = NULL; 587 PetscReal xi[4]; 588 PetscInt d, f, comp; 589 590 CHKERRQ(DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, invJ, &detJ)); 591 PetscCheckFalse(detJ <= 0.0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %D", (double)detJ, c); 592 CHKERRQ(DMPlexVecGetClosure(dm, NULL, xLocal, c, NULL, &x)); 593 for (comp = 0; comp < ctx->dof; ++comp) a[p*ctx->dof+comp] = x[0*ctx->dof+comp]; 594 595 for (d = 0; d < ctx->dim; ++d) { 596 xi[d] = 0.0; 597 for (f = 0; f < ctx->dim; ++f) xi[d] += invJ[d*ctx->dim+f]*0.5*PetscRealPart(coords[p*ctx->dim+f] - v0[f]); 598 for (comp = 0; comp < ctx->dof; ++comp) a[p*ctx->dof+comp] += PetscRealPart(x[order[d]*ctx->dof+comp] - x[0*ctx->dof+comp])*xi[d]; 599 } 600 CHKERRQ(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, NULL, &x)); 601 } 602 CHKERRQ(VecRestoreArray(v, &a)); 603 CHKERRQ(VecRestoreArrayRead(ctx->coords, &coords)); 604 CHKERRQ(PetscFree3(v0, J, invJ)); 605 PetscFunctionReturn(0); 606 } 607 608 static inline PetscErrorCode QuadMap_Private(SNES snes, Vec Xref, Vec Xreal, void *ctx) 609 { 610 const PetscScalar *vertices = (const PetscScalar*) ctx; 611 const PetscScalar x0 = vertices[0]; 612 const PetscScalar y0 = vertices[1]; 613 const PetscScalar x1 = vertices[2]; 614 const PetscScalar y1 = vertices[3]; 615 const PetscScalar x2 = vertices[4]; 616 const PetscScalar y2 = vertices[5]; 617 const PetscScalar x3 = vertices[6]; 618 const PetscScalar y3 = vertices[7]; 619 const PetscScalar f_1 = x1 - x0; 620 const PetscScalar g_1 = y1 - y0; 621 const PetscScalar f_3 = x3 - x0; 622 const PetscScalar g_3 = y3 - y0; 623 const PetscScalar f_01 = x2 - x1 - x3 + x0; 624 const PetscScalar g_01 = y2 - y1 - y3 + y0; 625 const PetscScalar *ref; 626 PetscScalar *real; 627 628 PetscFunctionBegin; 629 CHKERRQ(VecGetArrayRead(Xref, &ref)); 630 CHKERRQ(VecGetArray(Xreal, &real)); 631 { 632 const PetscScalar p0 = ref[0]; 633 const PetscScalar p1 = ref[1]; 634 635 real[0] = x0 + f_1 * p0 + f_3 * p1 + f_01 * p0 * p1; 636 real[1] = y0 + g_1 * p0 + g_3 * p1 + g_01 * p0 * p1; 637 } 638 CHKERRQ(PetscLogFlops(28)); 639 CHKERRQ(VecRestoreArrayRead(Xref, &ref)); 640 CHKERRQ(VecRestoreArray(Xreal, &real)); 641 PetscFunctionReturn(0); 642 } 643 644 #include <petsc/private/dmimpl.h> 645 static inline PetscErrorCode QuadJacobian_Private(SNES snes, Vec Xref, Mat J, Mat M, void *ctx) 646 { 647 const PetscScalar *vertices = (const PetscScalar*) ctx; 648 const PetscScalar x0 = vertices[0]; 649 const PetscScalar y0 = vertices[1]; 650 const PetscScalar x1 = vertices[2]; 651 const PetscScalar y1 = vertices[3]; 652 const PetscScalar x2 = vertices[4]; 653 const PetscScalar y2 = vertices[5]; 654 const PetscScalar x3 = vertices[6]; 655 const PetscScalar y3 = vertices[7]; 656 const PetscScalar f_01 = x2 - x1 - x3 + x0; 657 const PetscScalar g_01 = y2 - y1 - y3 + y0; 658 const PetscScalar *ref; 659 660 PetscFunctionBegin; 661 CHKERRQ(VecGetArrayRead(Xref, &ref)); 662 { 663 const PetscScalar x = ref[0]; 664 const PetscScalar y = ref[1]; 665 const PetscInt rows[2] = {0, 1}; 666 PetscScalar values[4]; 667 668 values[0] = (x1 - x0 + f_01*y) * 0.5; values[1] = (x3 - x0 + f_01*x) * 0.5; 669 values[2] = (y1 - y0 + g_01*y) * 0.5; values[3] = (y3 - y0 + g_01*x) * 0.5; 670 CHKERRQ(MatSetValues(J, 2, rows, 2, rows, values, INSERT_VALUES)); 671 } 672 CHKERRQ(PetscLogFlops(30)); 673 CHKERRQ(VecRestoreArrayRead(Xref, &ref)); 674 CHKERRQ(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY)); 675 CHKERRQ(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY)); 676 PetscFunctionReturn(0); 677 } 678 679 static inline PetscErrorCode DMInterpolate_Quad_Private(DMInterpolationInfo ctx, DM dm, Vec xLocal, Vec v) 680 { 681 DM dmCoord; 682 PetscFE fem = NULL; 683 SNES snes; 684 KSP ksp; 685 PC pc; 686 Vec coordsLocal, r, ref, real; 687 Mat J; 688 PetscTabulation T = NULL; 689 const PetscScalar *coords; 690 PetscScalar *a; 691 PetscReal xir[2] = {0., 0.}; 692 PetscInt Nf, p; 693 const PetscInt dof = ctx->dof; 694 695 PetscFunctionBegin; 696 CHKERRQ(DMGetNumFields(dm, &Nf)); 697 if (Nf) { 698 PetscObject obj; 699 PetscClassId id; 700 701 CHKERRQ(DMGetField(dm, 0, NULL, &obj)); 702 CHKERRQ(PetscObjectGetClassId(obj, &id)); 703 if (id == PETSCFE_CLASSID) {fem = (PetscFE) obj; CHKERRQ(PetscFECreateTabulation(fem, 1, 1, xir, 0, &T));} 704 } 705 CHKERRQ(DMGetCoordinatesLocal(dm, &coordsLocal)); 706 CHKERRQ(DMGetCoordinateDM(dm, &dmCoord)); 707 CHKERRQ(SNESCreate(PETSC_COMM_SELF, &snes)); 708 CHKERRQ(SNESSetOptionsPrefix(snes, "quad_interp_")); 709 CHKERRQ(VecCreate(PETSC_COMM_SELF, &r)); 710 CHKERRQ(VecSetSizes(r, 2, 2)); 711 CHKERRQ(VecSetType(r,dm->vectype)); 712 CHKERRQ(VecDuplicate(r, &ref)); 713 CHKERRQ(VecDuplicate(r, &real)); 714 CHKERRQ(MatCreate(PETSC_COMM_SELF, &J)); 715 CHKERRQ(MatSetSizes(J, 2, 2, 2, 2)); 716 CHKERRQ(MatSetType(J, MATSEQDENSE)); 717 CHKERRQ(MatSetUp(J)); 718 CHKERRQ(SNESSetFunction(snes, r, QuadMap_Private, NULL)); 719 CHKERRQ(SNESSetJacobian(snes, J, J, QuadJacobian_Private, NULL)); 720 CHKERRQ(SNESGetKSP(snes, &ksp)); 721 CHKERRQ(KSPGetPC(ksp, &pc)); 722 CHKERRQ(PCSetType(pc, PCLU)); 723 CHKERRQ(SNESSetFromOptions(snes)); 724 725 CHKERRQ(VecGetArrayRead(ctx->coords, &coords)); 726 CHKERRQ(VecGetArray(v, &a)); 727 for (p = 0; p < ctx->n; ++p) { 728 PetscScalar *x = NULL, *vertices = NULL; 729 PetscScalar *xi; 730 PetscInt c = ctx->cells[p], comp, coordSize, xSize; 731 732 /* Can make this do all points at once */ 733 CHKERRQ(DMPlexVecGetClosure(dmCoord, NULL, coordsLocal, c, &coordSize, &vertices)); 734 PetscCheckFalse(4*2 != coordSize,ctx->comm, PETSC_ERR_ARG_SIZ, "Invalid closure size %D should be %d", coordSize, 4*2); 735 CHKERRQ(DMPlexVecGetClosure(dm, NULL, xLocal, c, &xSize, &x)); 736 CHKERRQ(SNESSetFunction(snes, NULL, NULL, vertices)); 737 CHKERRQ(SNESSetJacobian(snes, NULL, NULL, NULL, vertices)); 738 CHKERRQ(VecGetArray(real, &xi)); 739 xi[0] = coords[p*ctx->dim+0]; 740 xi[1] = coords[p*ctx->dim+1]; 741 CHKERRQ(VecRestoreArray(real, &xi)); 742 CHKERRQ(SNESSolve(snes, real, ref)); 743 CHKERRQ(VecGetArray(ref, &xi)); 744 xir[0] = PetscRealPart(xi[0]); 745 xir[1] = PetscRealPart(xi[1]); 746 if (4*dof == xSize) { 747 for (comp = 0; comp < dof; ++comp) 748 a[p*dof+comp] = x[0*dof+comp]*(1 - xir[0])*(1 - xir[1]) + x[1*dof+comp]*xir[0]*(1 - xir[1]) + x[2*dof+comp]*xir[0]*xir[1] + x[3*dof+comp]*(1 - xir[0])*xir[1]; 749 } else if (dof == xSize) { 750 for (comp = 0; comp < dof; ++comp) a[p*dof+comp] = x[0*dof+comp]; 751 } else { 752 PetscInt d; 753 754 PetscCheck(fem, ctx->comm, PETSC_ERR_ARG_WRONG, "Cannot have a higher order interpolant if the discretization is not PetscFE"); 755 xir[0] = 2.0*xir[0] - 1.0; xir[1] = 2.0*xir[1] - 1.0; 756 CHKERRQ(PetscFEComputeTabulation(fem, 1, xir, 0, T)); 757 for (comp = 0; comp < dof; ++comp) { 758 a[p*dof+comp] = 0.0; 759 for (d = 0; d < xSize/dof; ++d) { 760 a[p*dof+comp] += x[d*dof+comp]*T->T[0][d*dof+comp]; 761 } 762 } 763 } 764 CHKERRQ(VecRestoreArray(ref, &xi)); 765 CHKERRQ(DMPlexVecRestoreClosure(dmCoord, NULL, coordsLocal, c, &coordSize, &vertices)); 766 CHKERRQ(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, &xSize, &x)); 767 } 768 CHKERRQ(PetscTabulationDestroy(&T)); 769 CHKERRQ(VecRestoreArray(v, &a)); 770 CHKERRQ(VecRestoreArrayRead(ctx->coords, &coords)); 771 772 CHKERRQ(SNESDestroy(&snes)); 773 CHKERRQ(VecDestroy(&r)); 774 CHKERRQ(VecDestroy(&ref)); 775 CHKERRQ(VecDestroy(&real)); 776 CHKERRQ(MatDestroy(&J)); 777 PetscFunctionReturn(0); 778 } 779 780 static inline PetscErrorCode HexMap_Private(SNES snes, Vec Xref, Vec Xreal, void *ctx) 781 { 782 const PetscScalar *vertices = (const PetscScalar*) ctx; 783 const PetscScalar x0 = vertices[0]; 784 const PetscScalar y0 = vertices[1]; 785 const PetscScalar z0 = vertices[2]; 786 const PetscScalar x1 = vertices[9]; 787 const PetscScalar y1 = vertices[10]; 788 const PetscScalar z1 = vertices[11]; 789 const PetscScalar x2 = vertices[6]; 790 const PetscScalar y2 = vertices[7]; 791 const PetscScalar z2 = vertices[8]; 792 const PetscScalar x3 = vertices[3]; 793 const PetscScalar y3 = vertices[4]; 794 const PetscScalar z3 = vertices[5]; 795 const PetscScalar x4 = vertices[12]; 796 const PetscScalar y4 = vertices[13]; 797 const PetscScalar z4 = vertices[14]; 798 const PetscScalar x5 = vertices[15]; 799 const PetscScalar y5 = vertices[16]; 800 const PetscScalar z5 = vertices[17]; 801 const PetscScalar x6 = vertices[18]; 802 const PetscScalar y6 = vertices[19]; 803 const PetscScalar z6 = vertices[20]; 804 const PetscScalar x7 = vertices[21]; 805 const PetscScalar y7 = vertices[22]; 806 const PetscScalar z7 = vertices[23]; 807 const PetscScalar f_1 = x1 - x0; 808 const PetscScalar g_1 = y1 - y0; 809 const PetscScalar h_1 = z1 - z0; 810 const PetscScalar f_3 = x3 - x0; 811 const PetscScalar g_3 = y3 - y0; 812 const PetscScalar h_3 = z3 - z0; 813 const PetscScalar f_4 = x4 - x0; 814 const PetscScalar g_4 = y4 - y0; 815 const PetscScalar h_4 = z4 - z0; 816 const PetscScalar f_01 = x2 - x1 - x3 + x0; 817 const PetscScalar g_01 = y2 - y1 - y3 + y0; 818 const PetscScalar h_01 = z2 - z1 - z3 + z0; 819 const PetscScalar f_12 = x7 - x3 - x4 + x0; 820 const PetscScalar g_12 = y7 - y3 - y4 + y0; 821 const PetscScalar h_12 = z7 - z3 - z4 + z0; 822 const PetscScalar f_02 = x5 - x1 - x4 + x0; 823 const PetscScalar g_02 = y5 - y1 - y4 + y0; 824 const PetscScalar h_02 = z5 - z1 - z4 + z0; 825 const PetscScalar f_012 = x6 - x0 + x1 - x2 + x3 + x4 - x5 - x7; 826 const PetscScalar g_012 = y6 - y0 + y1 - y2 + y3 + y4 - y5 - y7; 827 const PetscScalar h_012 = z6 - z0 + z1 - z2 + z3 + z4 - z5 - z7; 828 const PetscScalar *ref; 829 PetscScalar *real; 830 831 PetscFunctionBegin; 832 CHKERRQ(VecGetArrayRead(Xref, &ref)); 833 CHKERRQ(VecGetArray(Xreal, &real)); 834 { 835 const PetscScalar p0 = ref[0]; 836 const PetscScalar p1 = ref[1]; 837 const PetscScalar p2 = ref[2]; 838 839 real[0] = x0 + f_1*p0 + f_3*p1 + f_4*p2 + f_01*p0*p1 + f_12*p1*p2 + f_02*p0*p2 + f_012*p0*p1*p2; 840 real[1] = y0 + g_1*p0 + g_3*p1 + g_4*p2 + g_01*p0*p1 + g_01*p0*p1 + g_12*p1*p2 + g_02*p0*p2 + g_012*p0*p1*p2; 841 real[2] = z0 + h_1*p0 + h_3*p1 + h_4*p2 + h_01*p0*p1 + h_01*p0*p1 + h_12*p1*p2 + h_02*p0*p2 + h_012*p0*p1*p2; 842 } 843 CHKERRQ(PetscLogFlops(114)); 844 CHKERRQ(VecRestoreArrayRead(Xref, &ref)); 845 CHKERRQ(VecRestoreArray(Xreal, &real)); 846 PetscFunctionReturn(0); 847 } 848 849 static inline PetscErrorCode HexJacobian_Private(SNES snes, Vec Xref, Mat J, Mat M, void *ctx) 850 { 851 const PetscScalar *vertices = (const PetscScalar*) ctx; 852 const PetscScalar x0 = vertices[0]; 853 const PetscScalar y0 = vertices[1]; 854 const PetscScalar z0 = vertices[2]; 855 const PetscScalar x1 = vertices[9]; 856 const PetscScalar y1 = vertices[10]; 857 const PetscScalar z1 = vertices[11]; 858 const PetscScalar x2 = vertices[6]; 859 const PetscScalar y2 = vertices[7]; 860 const PetscScalar z2 = vertices[8]; 861 const PetscScalar x3 = vertices[3]; 862 const PetscScalar y3 = vertices[4]; 863 const PetscScalar z3 = vertices[5]; 864 const PetscScalar x4 = vertices[12]; 865 const PetscScalar y4 = vertices[13]; 866 const PetscScalar z4 = vertices[14]; 867 const PetscScalar x5 = vertices[15]; 868 const PetscScalar y5 = vertices[16]; 869 const PetscScalar z5 = vertices[17]; 870 const PetscScalar x6 = vertices[18]; 871 const PetscScalar y6 = vertices[19]; 872 const PetscScalar z6 = vertices[20]; 873 const PetscScalar x7 = vertices[21]; 874 const PetscScalar y7 = vertices[22]; 875 const PetscScalar z7 = vertices[23]; 876 const PetscScalar f_xy = x2 - x1 - x3 + x0; 877 const PetscScalar g_xy = y2 - y1 - y3 + y0; 878 const PetscScalar h_xy = z2 - z1 - z3 + z0; 879 const PetscScalar f_yz = x7 - x3 - x4 + x0; 880 const PetscScalar g_yz = y7 - y3 - y4 + y0; 881 const PetscScalar h_yz = z7 - z3 - z4 + z0; 882 const PetscScalar f_xz = x5 - x1 - x4 + x0; 883 const PetscScalar g_xz = y5 - y1 - y4 + y0; 884 const PetscScalar h_xz = z5 - z1 - z4 + z0; 885 const PetscScalar f_xyz = x6 - x0 + x1 - x2 + x3 + x4 - x5 - x7; 886 const PetscScalar g_xyz = y6 - y0 + y1 - y2 + y3 + y4 - y5 - y7; 887 const PetscScalar h_xyz = z6 - z0 + z1 - z2 + z3 + z4 - z5 - z7; 888 const PetscScalar *ref; 889 890 PetscFunctionBegin; 891 CHKERRQ(VecGetArrayRead(Xref, &ref)); 892 { 893 const PetscScalar x = ref[0]; 894 const PetscScalar y = ref[1]; 895 const PetscScalar z = ref[2]; 896 const PetscInt rows[3] = {0, 1, 2}; 897 PetscScalar values[9]; 898 899 values[0] = (x1 - x0 + f_xy*y + f_xz*z + f_xyz*y*z) / 2.0; 900 values[1] = (x3 - x0 + f_xy*x + f_yz*z + f_xyz*x*z) / 2.0; 901 values[2] = (x4 - x0 + f_yz*y + f_xz*x + f_xyz*x*y) / 2.0; 902 values[3] = (y1 - y0 + g_xy*y + g_xz*z + g_xyz*y*z) / 2.0; 903 values[4] = (y3 - y0 + g_xy*x + g_yz*z + g_xyz*x*z) / 2.0; 904 values[5] = (y4 - y0 + g_yz*y + g_xz*x + g_xyz*x*y) / 2.0; 905 values[6] = (z1 - z0 + h_xy*y + h_xz*z + h_xyz*y*z) / 2.0; 906 values[7] = (z3 - z0 + h_xy*x + h_yz*z + h_xyz*x*z) / 2.0; 907 values[8] = (z4 - z0 + h_yz*y + h_xz*x + h_xyz*x*y) / 2.0; 908 909 CHKERRQ(MatSetValues(J, 3, rows, 3, rows, values, INSERT_VALUES)); 910 } 911 CHKERRQ(PetscLogFlops(152)); 912 CHKERRQ(VecRestoreArrayRead(Xref, &ref)); 913 CHKERRQ(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY)); 914 CHKERRQ(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY)); 915 PetscFunctionReturn(0); 916 } 917 918 static inline PetscErrorCode DMInterpolate_Hex_Private(DMInterpolationInfo ctx, DM dm, Vec xLocal, Vec v) 919 { 920 DM dmCoord; 921 SNES snes; 922 KSP ksp; 923 PC pc; 924 Vec coordsLocal, r, ref, real; 925 Mat J; 926 const PetscScalar *coords; 927 PetscScalar *a; 928 PetscInt p; 929 930 PetscFunctionBegin; 931 CHKERRQ(DMGetCoordinatesLocal(dm, &coordsLocal)); 932 CHKERRQ(DMGetCoordinateDM(dm, &dmCoord)); 933 CHKERRQ(SNESCreate(PETSC_COMM_SELF, &snes)); 934 CHKERRQ(SNESSetOptionsPrefix(snes, "hex_interp_")); 935 CHKERRQ(VecCreate(PETSC_COMM_SELF, &r)); 936 CHKERRQ(VecSetSizes(r, 3, 3)); 937 CHKERRQ(VecSetType(r,dm->vectype)); 938 CHKERRQ(VecDuplicate(r, &ref)); 939 CHKERRQ(VecDuplicate(r, &real)); 940 CHKERRQ(MatCreate(PETSC_COMM_SELF, &J)); 941 CHKERRQ(MatSetSizes(J, 3, 3, 3, 3)); 942 CHKERRQ(MatSetType(J, MATSEQDENSE)); 943 CHKERRQ(MatSetUp(J)); 944 CHKERRQ(SNESSetFunction(snes, r, HexMap_Private, NULL)); 945 CHKERRQ(SNESSetJacobian(snes, J, J, HexJacobian_Private, NULL)); 946 CHKERRQ(SNESGetKSP(snes, &ksp)); 947 CHKERRQ(KSPGetPC(ksp, &pc)); 948 CHKERRQ(PCSetType(pc, PCLU)); 949 CHKERRQ(SNESSetFromOptions(snes)); 950 951 CHKERRQ(VecGetArrayRead(ctx->coords, &coords)); 952 CHKERRQ(VecGetArray(v, &a)); 953 for (p = 0; p < ctx->n; ++p) { 954 PetscScalar *x = NULL, *vertices = NULL; 955 PetscScalar *xi; 956 PetscReal xir[3]; 957 PetscInt c = ctx->cells[p], comp, coordSize, xSize; 958 959 /* Can make this do all points at once */ 960 CHKERRQ(DMPlexVecGetClosure(dmCoord, NULL, coordsLocal, c, &coordSize, &vertices)); 961 PetscCheck(8*3 == coordSize,ctx->comm, PETSC_ERR_ARG_SIZ, "Invalid coordinate closure size %" PetscInt_FMT " should be %d", coordSize, 8*3); 962 CHKERRQ(DMPlexVecGetClosure(dm, NULL, xLocal, c, &xSize, &x)); 963 PetscCheck((8*ctx->dof == xSize) || (ctx->dof == xSize),ctx->comm, PETSC_ERR_ARG_SIZ, "Invalid input closure size %" PetscInt_FMT " should be %" PetscInt_FMT " or %" PetscInt_FMT, xSize, 8*ctx->dof, ctx->dof); 964 CHKERRQ(SNESSetFunction(snes, NULL, NULL, vertices)); 965 CHKERRQ(SNESSetJacobian(snes, NULL, NULL, NULL, vertices)); 966 CHKERRQ(VecGetArray(real, &xi)); 967 xi[0] = coords[p*ctx->dim+0]; 968 xi[1] = coords[p*ctx->dim+1]; 969 xi[2] = coords[p*ctx->dim+2]; 970 CHKERRQ(VecRestoreArray(real, &xi)); 971 CHKERRQ(SNESSolve(snes, real, ref)); 972 CHKERRQ(VecGetArray(ref, &xi)); 973 xir[0] = PetscRealPart(xi[0]); 974 xir[1] = PetscRealPart(xi[1]); 975 xir[2] = PetscRealPart(xi[2]); 976 if (8*ctx->dof == xSize) { 977 for (comp = 0; comp < ctx->dof; ++comp) { 978 a[p*ctx->dof+comp] = 979 x[0*ctx->dof+comp]*(1-xir[0])*(1-xir[1])*(1-xir[2]) + 980 x[3*ctx->dof+comp]* xir[0]*(1-xir[1])*(1-xir[2]) + 981 x[2*ctx->dof+comp]* xir[0]* xir[1]*(1-xir[2]) + 982 x[1*ctx->dof+comp]*(1-xir[0])* xir[1]*(1-xir[2]) + 983 x[4*ctx->dof+comp]*(1-xir[0])*(1-xir[1])* xir[2] + 984 x[5*ctx->dof+comp]* xir[0]*(1-xir[1])* xir[2] + 985 x[6*ctx->dof+comp]* xir[0]* xir[1]* xir[2] + 986 x[7*ctx->dof+comp]*(1-xir[0])* xir[1]* xir[2]; 987 } 988 } else { 989 for (comp = 0; comp < ctx->dof; ++comp) a[p*ctx->dof+comp] = x[0*ctx->dof+comp]; 990 } 991 CHKERRQ(VecRestoreArray(ref, &xi)); 992 CHKERRQ(DMPlexVecRestoreClosure(dmCoord, NULL, coordsLocal, c, &coordSize, &vertices)); 993 CHKERRQ(DMPlexVecRestoreClosure(dm, NULL, xLocal, c, &xSize, &x)); 994 } 995 CHKERRQ(VecRestoreArray(v, &a)); 996 CHKERRQ(VecRestoreArrayRead(ctx->coords, &coords)); 997 998 CHKERRQ(SNESDestroy(&snes)); 999 CHKERRQ(VecDestroy(&r)); 1000 CHKERRQ(VecDestroy(&ref)); 1001 CHKERRQ(VecDestroy(&real)); 1002 CHKERRQ(MatDestroy(&J)); 1003 PetscFunctionReturn(0); 1004 } 1005 1006 /*@C 1007 DMInterpolationEvaluate - Using the input from dm and x, calculates interpolated field values at the interpolation points. 1008 1009 Input Parameters: 1010 + ctx - The DMInterpolationInfo context 1011 . dm - The DM 1012 - x - The local vector containing the field to be interpolated 1013 1014 Output Parameters: 1015 . v - The vector containing the interpolated values 1016 1017 Note: A suitable v can be obtained using DMInterpolationGetVector(). 1018 1019 Level: beginner 1020 1021 .seealso: DMInterpolationGetVector(), DMInterpolationAddPoints(), DMInterpolationCreate() 1022 @*/ 1023 PetscErrorCode DMInterpolationEvaluate(DMInterpolationInfo ctx, DM dm, Vec x, Vec v) 1024 { 1025 PetscDS ds; 1026 PetscInt n, p, Nf, field; 1027 PetscBool useDS = PETSC_FALSE; 1028 1029 PetscFunctionBegin; 1030 PetscValidHeaderSpecific(dm, DM_CLASSID, 2); 1031 PetscValidHeaderSpecific(x, VEC_CLASSID, 3); 1032 PetscValidHeaderSpecific(v, VEC_CLASSID, 4); 1033 CHKERRQ(VecGetLocalSize(v, &n)); 1034 PetscCheckFalse(n != ctx->n*ctx->dof,ctx->comm, PETSC_ERR_ARG_SIZ, "Invalid input vector size %D should be %D", n, ctx->n*ctx->dof); 1035 if (!n) PetscFunctionReturn(0); 1036 CHKERRQ(DMGetDS(dm, &ds)); 1037 if (ds) { 1038 useDS = PETSC_TRUE; 1039 CHKERRQ(PetscDSGetNumFields(ds, &Nf)); 1040 for (field = 0; field < Nf; ++field) { 1041 PetscObject obj; 1042 PetscClassId id; 1043 1044 CHKERRQ(PetscDSGetDiscretization(ds, field, &obj)); 1045 CHKERRQ(PetscObjectGetClassId(obj, &id)); 1046 if (id != PETSCFE_CLASSID) {useDS = PETSC_FALSE; break;} 1047 } 1048 } 1049 if (useDS) { 1050 const PetscScalar *coords; 1051 PetscScalar *interpolant; 1052 PetscInt cdim, d; 1053 1054 CHKERRQ(DMGetCoordinateDim(dm, &cdim)); 1055 CHKERRQ(VecGetArrayRead(ctx->coords, &coords)); 1056 CHKERRQ(VecGetArrayWrite(v, &interpolant)); 1057 for (p = 0; p < ctx->n; ++p) { 1058 PetscReal pcoords[3], xi[3]; 1059 PetscScalar *xa = NULL; 1060 PetscInt coff = 0, foff = 0, clSize; 1061 1062 if (ctx->cells[p] < 0) continue; 1063 for (d = 0; d < cdim; ++d) pcoords[d] = PetscRealPart(coords[p*cdim+d]); 1064 CHKERRQ(DMPlexCoordinatesToReference(dm, ctx->cells[p], 1, pcoords, xi)); 1065 CHKERRQ(DMPlexVecGetClosure(dm, NULL, x, ctx->cells[p], &clSize, &xa)); 1066 for (field = 0; field < Nf; ++field) { 1067 PetscTabulation T; 1068 PetscFE fe; 1069 1070 CHKERRQ(PetscDSGetDiscretization(ds, field, (PetscObject *) &fe)); 1071 CHKERRQ(PetscFECreateTabulation(fe, 1, 1, xi, 0, &T)); 1072 { 1073 const PetscReal *basis = T->T[0]; 1074 const PetscInt Nb = T->Nb; 1075 const PetscInt Nc = T->Nc; 1076 PetscInt f, fc; 1077 1078 for (fc = 0; fc < Nc; ++fc) { 1079 interpolant[p*ctx->dof+coff+fc] = 0.0; 1080 for (f = 0; f < Nb; ++f) { 1081 interpolant[p*ctx->dof+coff+fc] += xa[foff+f]*basis[(0*Nb + f)*Nc + fc]; 1082 } 1083 } 1084 coff += Nc; 1085 foff += Nb; 1086 } 1087 CHKERRQ(PetscTabulationDestroy(&T)); 1088 } 1089 CHKERRQ(DMPlexVecRestoreClosure(dm, NULL, x, ctx->cells[p], &clSize, &xa)); 1090 PetscCheckFalse(coff != ctx->dof,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Total components %D != %D dof specified for interpolation", coff, ctx->dof); 1091 PetscCheckFalse(foff != clSize,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Total FE space size %D != %D closure size", foff, clSize); 1092 } 1093 CHKERRQ(VecRestoreArrayRead(ctx->coords, &coords)); 1094 CHKERRQ(VecRestoreArrayWrite(v, &interpolant)); 1095 } else { 1096 DMPolytopeType ct; 1097 1098 /* TODO Check each cell individually */ 1099 CHKERRQ(DMPlexGetCellType(dm, ctx->cells[0], &ct)); 1100 switch (ct) { 1101 case DM_POLYTOPE_SEGMENT: CHKERRQ(DMInterpolate_Segment_Private(ctx, dm, x, v));break; 1102 case DM_POLYTOPE_TRIANGLE: CHKERRQ(DMInterpolate_Triangle_Private(ctx, dm, x, v));break; 1103 case DM_POLYTOPE_QUADRILATERAL: CHKERRQ(DMInterpolate_Quad_Private(ctx, dm, x, v));break; 1104 case DM_POLYTOPE_TETRAHEDRON: CHKERRQ(DMInterpolate_Tetrahedron_Private(ctx, dm, x, v));break; 1105 case DM_POLYTOPE_HEXAHEDRON: CHKERRQ(DMInterpolate_Hex_Private(ctx, dm, x, v));break; 1106 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for cell type %s", DMPolytopeTypes[PetscMax(0, PetscMin(ct, DM_NUM_POLYTOPES))]); 1107 } 1108 } 1109 PetscFunctionReturn(0); 1110 } 1111 1112 /*@C 1113 DMInterpolationDestroy - Destroys a DMInterpolationInfo context 1114 1115 Collective on ctx 1116 1117 Input Parameter: 1118 . ctx - the context 1119 1120 Level: beginner 1121 1122 .seealso: DMInterpolationEvaluate(), DMInterpolationAddPoints(), DMInterpolationCreate() 1123 @*/ 1124 PetscErrorCode DMInterpolationDestroy(DMInterpolationInfo *ctx) 1125 { 1126 PetscFunctionBegin; 1127 PetscValidPointer(ctx, 1); 1128 CHKERRQ(VecDestroy(&(*ctx)->coords)); 1129 CHKERRQ(PetscFree((*ctx)->points)); 1130 CHKERRQ(PetscFree((*ctx)->cells)); 1131 CHKERRQ(PetscFree(*ctx)); 1132 *ctx = NULL; 1133 PetscFunctionReturn(0); 1134 } 1135 1136 /*@C 1137 SNESMonitorFields - Monitors the residual for each field separately 1138 1139 Collective on SNES 1140 1141 Input Parameters: 1142 + snes - the SNES context 1143 . its - iteration number 1144 . fgnorm - 2-norm of residual 1145 - vf - PetscViewerAndFormat of type ASCII 1146 1147 Notes: 1148 This routine prints the residual norm at each iteration. 1149 1150 Level: intermediate 1151 1152 .seealso: SNESMonitorSet(), SNESMonitorDefault() 1153 @*/ 1154 PetscErrorCode SNESMonitorFields(SNES snes, PetscInt its, PetscReal fgnorm, PetscViewerAndFormat *vf) 1155 { 1156 PetscViewer viewer = vf->viewer; 1157 Vec res; 1158 DM dm; 1159 PetscSection s; 1160 const PetscScalar *r; 1161 PetscReal *lnorms, *norms; 1162 PetscInt numFields, f, pStart, pEnd, p; 1163 1164 PetscFunctionBegin; 1165 PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,4); 1166 CHKERRQ(SNESGetFunction(snes, &res, NULL, NULL)); 1167 CHKERRQ(SNESGetDM(snes, &dm)); 1168 CHKERRQ(DMGetLocalSection(dm, &s)); 1169 CHKERRQ(PetscSectionGetNumFields(s, &numFields)); 1170 CHKERRQ(PetscSectionGetChart(s, &pStart, &pEnd)); 1171 CHKERRQ(PetscCalloc2(numFields, &lnorms, numFields, &norms)); 1172 CHKERRQ(VecGetArrayRead(res, &r)); 1173 for (p = pStart; p < pEnd; ++p) { 1174 for (f = 0; f < numFields; ++f) { 1175 PetscInt fdof, foff, d; 1176 1177 CHKERRQ(PetscSectionGetFieldDof(s, p, f, &fdof)); 1178 CHKERRQ(PetscSectionGetFieldOffset(s, p, f, &foff)); 1179 for (d = 0; d < fdof; ++d) lnorms[f] += PetscRealPart(PetscSqr(r[foff+d])); 1180 } 1181 } 1182 CHKERRQ(VecRestoreArrayRead(res, &r)); 1183 CHKERRMPI(MPIU_Allreduce(lnorms, norms, numFields, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject) dm))); 1184 CHKERRQ(PetscViewerPushFormat(viewer,vf->format)); 1185 CHKERRQ(PetscViewerASCIIAddTab(viewer, ((PetscObject) snes)->tablevel)); 1186 CHKERRQ(PetscViewerASCIIPrintf(viewer, "%3D SNES Function norm %14.12e [", its, (double) fgnorm)); 1187 for (f = 0; f < numFields; ++f) { 1188 if (f > 0) CHKERRQ(PetscViewerASCIIPrintf(viewer, ", ")); 1189 CHKERRQ(PetscViewerASCIIPrintf(viewer, "%14.12e", (double) PetscSqrtReal(norms[f]))); 1190 } 1191 CHKERRQ(PetscViewerASCIIPrintf(viewer, "]\n")); 1192 CHKERRQ(PetscViewerASCIISubtractTab(viewer, ((PetscObject) snes)->tablevel)); 1193 CHKERRQ(PetscViewerPopFormat(viewer)); 1194 CHKERRQ(PetscFree2(lnorms, norms)); 1195 PetscFunctionReturn(0); 1196 } 1197 1198 /********************* Residual Computation **************************/ 1199 1200 PetscErrorCode DMPlexGetAllCells_Internal(DM plex, IS *cellIS) 1201 { 1202 PetscInt depth; 1203 1204 PetscFunctionBegin; 1205 CHKERRQ(DMPlexGetDepth(plex, &depth)); 1206 CHKERRQ(DMGetStratumIS(plex, "dim", depth, cellIS)); 1207 if (!*cellIS) CHKERRQ(DMGetStratumIS(plex, "depth", depth, cellIS)); 1208 PetscFunctionReturn(0); 1209 } 1210 1211 /*@ 1212 DMPlexSNESComputeResidualFEM - Sums the local residual into vector F from the local input X using pointwise functions specified by the user 1213 1214 Input Parameters: 1215 + dm - The mesh 1216 . X - Local solution 1217 - user - The user context 1218 1219 Output Parameter: 1220 . F - Local output vector 1221 1222 Notes: 1223 The residual is summed into F; the caller is responsible for using VecZeroEntries() or otherwise ensuring that any data in F is intentional. 1224 1225 Level: developer 1226 1227 .seealso: DMPlexComputeJacobianAction() 1228 @*/ 1229 PetscErrorCode DMPlexSNESComputeResidualFEM(DM dm, Vec X, Vec F, void *user) 1230 { 1231 DM plex; 1232 IS allcellIS; 1233 PetscInt Nds, s; 1234 1235 PetscFunctionBegin; 1236 CHKERRQ(DMSNESConvertPlex(dm, &plex, PETSC_TRUE)); 1237 CHKERRQ(DMPlexGetAllCells_Internal(plex, &allcellIS)); 1238 CHKERRQ(DMGetNumDS(dm, &Nds)); 1239 for (s = 0; s < Nds; ++s) { 1240 PetscDS ds; 1241 IS cellIS; 1242 PetscFormKey key; 1243 1244 CHKERRQ(DMGetRegionNumDS(dm, s, &key.label, NULL, &ds)); 1245 key.value = 0; 1246 key.field = 0; 1247 key.part = 0; 1248 if (!key.label) { 1249 CHKERRQ(PetscObjectReference((PetscObject) allcellIS)); 1250 cellIS = allcellIS; 1251 } else { 1252 IS pointIS; 1253 1254 key.value = 1; 1255 CHKERRQ(DMLabelGetStratumIS(key.label, key.value, &pointIS)); 1256 CHKERRQ(ISIntersect_Caching_Internal(allcellIS, pointIS, &cellIS)); 1257 CHKERRQ(ISDestroy(&pointIS)); 1258 } 1259 CHKERRQ(DMPlexComputeResidual_Internal(plex, key, cellIS, PETSC_MIN_REAL, X, NULL, 0.0, F, user)); 1260 CHKERRQ(ISDestroy(&cellIS)); 1261 } 1262 CHKERRQ(ISDestroy(&allcellIS)); 1263 CHKERRQ(DMDestroy(&plex)); 1264 PetscFunctionReturn(0); 1265 } 1266 1267 PetscErrorCode DMSNESComputeResidual(DM dm, Vec X, Vec F, void *user) 1268 { 1269 DM plex; 1270 IS allcellIS; 1271 PetscInt Nds, s; 1272 1273 PetscFunctionBegin; 1274 CHKERRQ(DMSNESConvertPlex(dm, &plex, PETSC_TRUE)); 1275 CHKERRQ(DMPlexGetAllCells_Internal(plex, &allcellIS)); 1276 CHKERRQ(DMGetNumDS(dm, &Nds)); 1277 for (s = 0; s < Nds; ++s) { 1278 PetscDS ds; 1279 DMLabel label; 1280 IS cellIS; 1281 1282 CHKERRQ(DMGetRegionNumDS(dm, s, &label, NULL, &ds)); 1283 { 1284 PetscWeakFormKind resmap[2] = {PETSC_WF_F0, PETSC_WF_F1}; 1285 PetscWeakForm wf; 1286 PetscInt Nm = 2, m, Nk = 0, k, kp, off = 0; 1287 PetscFormKey *reskeys; 1288 1289 /* Get unique residual keys */ 1290 for (m = 0; m < Nm; ++m) { 1291 PetscInt Nkm; 1292 CHKERRQ(PetscHMapFormGetSize(ds->wf->form[resmap[m]], &Nkm)); 1293 Nk += Nkm; 1294 } 1295 CHKERRQ(PetscMalloc1(Nk, &reskeys)); 1296 for (m = 0; m < Nm; ++m) { 1297 CHKERRQ(PetscHMapFormGetKeys(ds->wf->form[resmap[m]], &off, reskeys)); 1298 } 1299 PetscCheckFalse(off != Nk,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Number of keys %D should be %D", off, Nk); 1300 CHKERRQ(PetscFormKeySort(Nk, reskeys)); 1301 for (k = 0, kp = 1; kp < Nk; ++kp) { 1302 if ((reskeys[k].label != reskeys[kp].label) || (reskeys[k].value != reskeys[kp].value)) { 1303 ++k; 1304 if (kp != k) reskeys[k] = reskeys[kp]; 1305 } 1306 } 1307 Nk = k; 1308 1309 CHKERRQ(PetscDSGetWeakForm(ds, &wf)); 1310 for (k = 0; k < Nk; ++k) { 1311 DMLabel label = reskeys[k].label; 1312 PetscInt val = reskeys[k].value; 1313 1314 if (!label) { 1315 CHKERRQ(PetscObjectReference((PetscObject) allcellIS)); 1316 cellIS = allcellIS; 1317 } else { 1318 IS pointIS; 1319 1320 CHKERRQ(DMLabelGetStratumIS(label, val, &pointIS)); 1321 CHKERRQ(ISIntersect_Caching_Internal(allcellIS, pointIS, &cellIS)); 1322 CHKERRQ(ISDestroy(&pointIS)); 1323 } 1324 CHKERRQ(DMPlexComputeResidual_Internal(plex, reskeys[k], cellIS, PETSC_MIN_REAL, X, NULL, 0.0, F, user)); 1325 CHKERRQ(ISDestroy(&cellIS)); 1326 } 1327 CHKERRQ(PetscFree(reskeys)); 1328 } 1329 } 1330 CHKERRQ(ISDestroy(&allcellIS)); 1331 CHKERRQ(DMDestroy(&plex)); 1332 PetscFunctionReturn(0); 1333 } 1334 1335 /*@ 1336 DMPlexSNESComputeBoundaryFEM - Form the boundary values for the local input X 1337 1338 Input Parameters: 1339 + dm - The mesh 1340 - user - The user context 1341 1342 Output Parameter: 1343 . X - Local solution 1344 1345 Level: developer 1346 1347 .seealso: DMPlexComputeJacobianAction() 1348 @*/ 1349 PetscErrorCode DMPlexSNESComputeBoundaryFEM(DM dm, Vec X, void *user) 1350 { 1351 DM plex; 1352 1353 PetscFunctionBegin; 1354 CHKERRQ(DMSNESConvertPlex(dm,&plex,PETSC_TRUE)); 1355 CHKERRQ(DMPlexInsertBoundaryValues(plex, PETSC_TRUE, X, PETSC_MIN_REAL, NULL, NULL, NULL)); 1356 CHKERRQ(DMDestroy(&plex)); 1357 PetscFunctionReturn(0); 1358 } 1359 1360 /*@ 1361 DMSNESComputeJacobianAction - Compute the action of the Jacobian J(X) on Y 1362 1363 Input Parameters: 1364 + dm - The DM 1365 . X - Local solution vector 1366 . Y - Local input vector 1367 - user - The user context 1368 1369 Output Parameter: 1370 . F - lcoal output vector 1371 1372 Level: developer 1373 1374 Notes: 1375 Users will typically use DMSNESCreateJacobianMF() followed by MatMult() instead of calling this routine directly. 1376 1377 .seealso: DMSNESCreateJacobianMF(), DMPlexSNESComputeResidualFEM() 1378 @*/ 1379 PetscErrorCode DMSNESComputeJacobianAction(DM dm, Vec X, Vec Y, Vec F, void *user) 1380 { 1381 DM plex; 1382 IS allcellIS; 1383 PetscInt Nds, s; 1384 1385 PetscFunctionBegin; 1386 CHKERRQ(DMSNESConvertPlex(dm, &plex, PETSC_TRUE)); 1387 CHKERRQ(DMPlexGetAllCells_Internal(plex, &allcellIS)); 1388 CHKERRQ(DMGetNumDS(dm, &Nds)); 1389 for (s = 0; s < Nds; ++s) { 1390 PetscDS ds; 1391 DMLabel label; 1392 IS cellIS; 1393 1394 CHKERRQ(DMGetRegionNumDS(dm, s, &label, NULL, &ds)); 1395 { 1396 PetscWeakFormKind jacmap[4] = {PETSC_WF_G0, PETSC_WF_G1, PETSC_WF_G2, PETSC_WF_G3}; 1397 PetscWeakForm wf; 1398 PetscInt Nm = 4, m, Nk = 0, k, kp, off = 0; 1399 PetscFormKey *jackeys; 1400 1401 /* Get unique Jacobian keys */ 1402 for (m = 0; m < Nm; ++m) { 1403 PetscInt Nkm; 1404 CHKERRQ(PetscHMapFormGetSize(ds->wf->form[jacmap[m]], &Nkm)); 1405 Nk += Nkm; 1406 } 1407 CHKERRQ(PetscMalloc1(Nk, &jackeys)); 1408 for (m = 0; m < Nm; ++m) { 1409 CHKERRQ(PetscHMapFormGetKeys(ds->wf->form[jacmap[m]], &off, jackeys)); 1410 } 1411 PetscCheckFalse(off != Nk,PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Number of keys %D should be %D", off, Nk); 1412 CHKERRQ(PetscFormKeySort(Nk, jackeys)); 1413 for (k = 0, kp = 1; kp < Nk; ++kp) { 1414 if ((jackeys[k].label != jackeys[kp].label) || (jackeys[k].value != jackeys[kp].value)) { 1415 ++k; 1416 if (kp != k) jackeys[k] = jackeys[kp]; 1417 } 1418 } 1419 Nk = k; 1420 1421 CHKERRQ(PetscDSGetWeakForm(ds, &wf)); 1422 for (k = 0; k < Nk; ++k) { 1423 DMLabel label = jackeys[k].label; 1424 PetscInt val = jackeys[k].value; 1425 1426 if (!label) { 1427 CHKERRQ(PetscObjectReference((PetscObject) allcellIS)); 1428 cellIS = allcellIS; 1429 } else { 1430 IS pointIS; 1431 1432 CHKERRQ(DMLabelGetStratumIS(label, val, &pointIS)); 1433 CHKERRQ(ISIntersect_Caching_Internal(allcellIS, pointIS, &cellIS)); 1434 CHKERRQ(ISDestroy(&pointIS)); 1435 } 1436 CHKERRQ(DMPlexComputeJacobian_Action_Internal(plex, jackeys[k], cellIS, 0.0, 0.0, X, NULL, Y, F, user)); 1437 CHKERRQ(ISDestroy(&cellIS)); 1438 } 1439 CHKERRQ(PetscFree(jackeys)); 1440 } 1441 } 1442 CHKERRQ(ISDestroy(&allcellIS)); 1443 CHKERRQ(DMDestroy(&plex)); 1444 PetscFunctionReturn(0); 1445 } 1446 1447 /*@ 1448 DMPlexSNESComputeJacobianFEM - Form the local portion of the Jacobian matrix J at the local solution X using pointwise functions specified by the user. 1449 1450 Input Parameters: 1451 + dm - The mesh 1452 . X - Local input vector 1453 - user - The user context 1454 1455 Output Parameter: 1456 . Jac - Jacobian matrix 1457 1458 Note: 1459 We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator, 1460 like a GPU, or vectorize on a multicore machine. 1461 1462 Level: developer 1463 1464 .seealso: FormFunctionLocal() 1465 @*/ 1466 PetscErrorCode DMPlexSNESComputeJacobianFEM(DM dm, Vec X, Mat Jac, Mat JacP,void *user) 1467 { 1468 DM plex; 1469 IS allcellIS; 1470 PetscBool hasJac, hasPrec; 1471 PetscInt Nds, s; 1472 1473 PetscFunctionBegin; 1474 CHKERRQ(DMSNESConvertPlex(dm, &plex, PETSC_TRUE)); 1475 CHKERRQ(DMPlexGetAllCells_Internal(plex, &allcellIS)); 1476 CHKERRQ(DMGetNumDS(dm, &Nds)); 1477 for (s = 0; s < Nds; ++s) { 1478 PetscDS ds; 1479 IS cellIS; 1480 PetscFormKey key; 1481 1482 CHKERRQ(DMGetRegionNumDS(dm, s, &key.label, NULL, &ds)); 1483 key.value = 0; 1484 key.field = 0; 1485 key.part = 0; 1486 if (!key.label) { 1487 CHKERRQ(PetscObjectReference((PetscObject) allcellIS)); 1488 cellIS = allcellIS; 1489 } else { 1490 IS pointIS; 1491 1492 key.value = 1; 1493 CHKERRQ(DMLabelGetStratumIS(key.label, key.value, &pointIS)); 1494 CHKERRQ(ISIntersect_Caching_Internal(allcellIS, pointIS, &cellIS)); 1495 CHKERRQ(ISDestroy(&pointIS)); 1496 } 1497 if (!s) { 1498 CHKERRQ(PetscDSHasJacobian(ds, &hasJac)); 1499 CHKERRQ(PetscDSHasJacobianPreconditioner(ds, &hasPrec)); 1500 if (hasJac && hasPrec) CHKERRQ(MatZeroEntries(Jac)); 1501 CHKERRQ(MatZeroEntries(JacP)); 1502 } 1503 CHKERRQ(DMPlexComputeJacobian_Internal(plex, key, cellIS, 0.0, 0.0, X, NULL, Jac, JacP, user)); 1504 CHKERRQ(ISDestroy(&cellIS)); 1505 } 1506 CHKERRQ(ISDestroy(&allcellIS)); 1507 CHKERRQ(DMDestroy(&plex)); 1508 PetscFunctionReturn(0); 1509 } 1510 1511 struct _DMSNESJacobianMFCtx 1512 { 1513 DM dm; 1514 Vec X; 1515 void *ctx; 1516 }; 1517 1518 static PetscErrorCode DMSNESJacobianMF_Destroy_Private(Mat A) 1519 { 1520 struct _DMSNESJacobianMFCtx *ctx; 1521 1522 PetscFunctionBegin; 1523 CHKERRQ(MatShellGetContext(A, &ctx)); 1524 CHKERRQ(MatShellSetContext(A, NULL)); 1525 CHKERRQ(DMDestroy(&ctx->dm)); 1526 CHKERRQ(VecDestroy(&ctx->X)); 1527 CHKERRQ(PetscFree(ctx)); 1528 PetscFunctionReturn(0); 1529 } 1530 1531 static PetscErrorCode DMSNESJacobianMF_Mult_Private(Mat A, Vec Y, Vec Z) 1532 { 1533 struct _DMSNESJacobianMFCtx *ctx; 1534 1535 PetscFunctionBegin; 1536 CHKERRQ(MatShellGetContext(A, &ctx)); 1537 CHKERRQ(DMSNESComputeJacobianAction(ctx->dm, ctx->X, Y, Z, ctx->ctx)); 1538 PetscFunctionReturn(0); 1539 } 1540 1541 /*@ 1542 DMSNESCreateJacobianMF - Create a Mat which computes the action of the Jacobian matrix-free 1543 1544 Collective on dm 1545 1546 Input Parameters: 1547 + dm - The DM 1548 . X - The evaluation point for the Jacobian 1549 - user - A user context, or NULL 1550 1551 Output Parameter: 1552 . J - The Mat 1553 1554 Level: advanced 1555 1556 Notes: 1557 Vec X is kept in Mat J, so updating X then updates the evaluation point. 1558 1559 .seealso: DMSNESComputeJacobianAction() 1560 @*/ 1561 PetscErrorCode DMSNESCreateJacobianMF(DM dm, Vec X, void *user, Mat *J) 1562 { 1563 struct _DMSNESJacobianMFCtx *ctx; 1564 PetscInt n, N; 1565 1566 PetscFunctionBegin; 1567 CHKERRQ(MatCreate(PetscObjectComm((PetscObject) dm), J)); 1568 CHKERRQ(MatSetType(*J, MATSHELL)); 1569 CHKERRQ(VecGetLocalSize(X, &n)); 1570 CHKERRQ(VecGetSize(X, &N)); 1571 CHKERRQ(MatSetSizes(*J, n, n, N, N)); 1572 CHKERRQ(PetscObjectReference((PetscObject) dm)); 1573 CHKERRQ(PetscObjectReference((PetscObject) X)); 1574 CHKERRQ(PetscMalloc1(1, &ctx)); 1575 ctx->dm = dm; 1576 ctx->X = X; 1577 ctx->ctx = user; 1578 CHKERRQ(MatShellSetContext(*J, ctx)); 1579 CHKERRQ(MatShellSetOperation(*J, MATOP_DESTROY, (void (*)(void)) DMSNESJacobianMF_Destroy_Private)); 1580 CHKERRQ(MatShellSetOperation(*J, MATOP_MULT, (void (*)(void)) DMSNESJacobianMF_Mult_Private)); 1581 PetscFunctionReturn(0); 1582 } 1583 1584 /* 1585 MatComputeNeumannOverlap - Computes an unassembled (Neumann) local overlapping Mat in nonlinear context. 1586 1587 Input Parameters: 1588 + X - SNES linearization point 1589 . ovl - index set of overlapping subdomains 1590 1591 Output Parameter: 1592 . J - unassembled (Neumann) local matrix 1593 1594 Level: intermediate 1595 1596 .seealso: DMCreateNeumannOverlap(), MATIS, PCHPDDMSetAuxiliaryMat() 1597 */ 1598 static PetscErrorCode MatComputeNeumannOverlap_Plex(Mat J, PetscReal t, Vec X, Vec X_t, PetscReal s, IS ovl, void *ctx) 1599 { 1600 SNES snes; 1601 Mat pJ; 1602 DM ovldm,origdm; 1603 DMSNES sdm; 1604 PetscErrorCode (*bfun)(DM,Vec,void*); 1605 PetscErrorCode (*jfun)(DM,Vec,Mat,Mat,void*); 1606 void *bctx,*jctx; 1607 1608 PetscFunctionBegin; 1609 CHKERRQ(PetscObjectQuery((PetscObject)ovl,"_DM_Overlap_HPDDM_MATIS",(PetscObject*)&pJ)); 1610 PetscCheckFalse(!pJ,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Missing overlapping Mat"); 1611 CHKERRQ(PetscObjectQuery((PetscObject)ovl,"_DM_Original_HPDDM",(PetscObject*)&origdm)); 1612 PetscCheckFalse(!origdm,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Missing original DM"); 1613 CHKERRQ(MatGetDM(pJ,&ovldm)); 1614 CHKERRQ(DMSNESGetBoundaryLocal(origdm,&bfun,&bctx)); 1615 CHKERRQ(DMSNESSetBoundaryLocal(ovldm,bfun,bctx)); 1616 CHKERRQ(DMSNESGetJacobianLocal(origdm,&jfun,&jctx)); 1617 CHKERRQ(DMSNESSetJacobianLocal(ovldm,jfun,jctx)); 1618 CHKERRQ(PetscObjectQuery((PetscObject)ovl,"_DM_Overlap_HPDDM_SNES",(PetscObject*)&snes)); 1619 if (!snes) { 1620 CHKERRQ(SNESCreate(PetscObjectComm((PetscObject)ovl),&snes)); 1621 CHKERRQ(SNESSetDM(snes,ovldm)); 1622 CHKERRQ(PetscObjectCompose((PetscObject)ovl,"_DM_Overlap_HPDDM_SNES",(PetscObject)snes)); 1623 CHKERRQ(PetscObjectDereference((PetscObject)snes)); 1624 } 1625 CHKERRQ(DMGetDMSNES(ovldm,&sdm)); 1626 CHKERRQ(VecLockReadPush(X)); 1627 PetscStackPush("SNES user Jacobian function"); 1628 CHKERRQ((*sdm->ops->computejacobian)(snes,X,pJ,pJ,sdm->jacobianctx)); 1629 PetscStackPop; 1630 CHKERRQ(VecLockReadPop(X)); 1631 /* this is a no-hop, just in case we decide to change the placeholder for the local Neumann matrix */ 1632 { 1633 Mat locpJ; 1634 1635 CHKERRQ(MatISGetLocalMat(pJ,&locpJ)); 1636 CHKERRQ(MatCopy(locpJ,J,SAME_NONZERO_PATTERN)); 1637 } 1638 PetscFunctionReturn(0); 1639 } 1640 1641 /*@ 1642 DMPlexSetSNESLocalFEM - Use DMPlex's internal FEM routines to compute SNES boundary values, residual, and Jacobian. 1643 1644 Input Parameters: 1645 + dm - The DM object 1646 . boundaryctx - the user context that will be passed to pointwise evaluation of boundary values (see PetscDSAddBoundary()) 1647 . residualctx - the user context that will be passed to pointwise evaluation of finite element residual computations (see PetscDSSetResidual()) 1648 - jacobianctx - the user context that will be passed to pointwise evaluation of finite element Jacobian construction (see PetscDSSetJacobian()) 1649 1650 Level: developer 1651 @*/ 1652 PetscErrorCode DMPlexSetSNESLocalFEM(DM dm, void *boundaryctx, void *residualctx, void *jacobianctx) 1653 { 1654 PetscFunctionBegin; 1655 CHKERRQ(DMSNESSetBoundaryLocal(dm,DMPlexSNESComputeBoundaryFEM,boundaryctx)); 1656 CHKERRQ(DMSNESSetFunctionLocal(dm,DMPlexSNESComputeResidualFEM,residualctx)); 1657 CHKERRQ(DMSNESSetJacobianLocal(dm,DMPlexSNESComputeJacobianFEM,jacobianctx)); 1658 CHKERRQ(PetscObjectComposeFunction((PetscObject)dm,"MatComputeNeumannOverlap_C",MatComputeNeumannOverlap_Plex)); 1659 PetscFunctionReturn(0); 1660 } 1661 1662 /*@C 1663 DMSNESCheckDiscretization - Check the discretization error of the exact solution 1664 1665 Input Parameters: 1666 + snes - the SNES object 1667 . dm - the DM 1668 . t - the time 1669 . u - a DM vector 1670 - tol - A tolerance for the check, or -1 to print the results instead 1671 1672 Output Parameters: 1673 . error - An array which holds the discretization error in each field, or NULL 1674 1675 Note: The user must call PetscDSSetExactSolution() beforehand 1676 1677 Level: developer 1678 1679 .seealso: DNSNESCheckFromOptions(), DMSNESCheckResidual(), DMSNESCheckJacobian(), PetscDSSetExactSolution() 1680 @*/ 1681 PetscErrorCode DMSNESCheckDiscretization(SNES snes, DM dm, PetscReal t, Vec u, PetscReal tol, PetscReal error[]) 1682 { 1683 PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx); 1684 void **ectxs; 1685 PetscReal *err; 1686 MPI_Comm comm; 1687 PetscInt Nf, f; 1688 1689 PetscFunctionBegin; 1690 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1); 1691 PetscValidHeaderSpecific(dm, DM_CLASSID, 2); 1692 PetscValidHeaderSpecific(u, VEC_CLASSID, 4); 1693 if (error) PetscValidRealPointer(error, 6); 1694 1695 CHKERRQ(DMComputeExactSolution(dm, t, u, NULL)); 1696 CHKERRQ(VecViewFromOptions(u, NULL, "-vec_view")); 1697 1698 CHKERRQ(PetscObjectGetComm((PetscObject) snes, &comm)); 1699 CHKERRQ(DMGetNumFields(dm, &Nf)); 1700 CHKERRQ(PetscCalloc3(Nf, &exacts, Nf, &ectxs, PetscMax(1, Nf), &err)); 1701 { 1702 PetscInt Nds, s; 1703 1704 CHKERRQ(DMGetNumDS(dm, &Nds)); 1705 for (s = 0; s < Nds; ++s) { 1706 PetscDS ds; 1707 DMLabel label; 1708 IS fieldIS; 1709 const PetscInt *fields; 1710 PetscInt dsNf, f; 1711 1712 CHKERRQ(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds)); 1713 CHKERRQ(PetscDSGetNumFields(ds, &dsNf)); 1714 CHKERRQ(ISGetIndices(fieldIS, &fields)); 1715 for (f = 0; f < dsNf; ++f) { 1716 const PetscInt field = fields[f]; 1717 CHKERRQ(PetscDSGetExactSolution(ds, field, &exacts[field], &ectxs[field])); 1718 } 1719 CHKERRQ(ISRestoreIndices(fieldIS, &fields)); 1720 } 1721 } 1722 if (Nf > 1) { 1723 CHKERRQ(DMComputeL2FieldDiff(dm, t, exacts, ectxs, u, err)); 1724 if (tol >= 0.0) { 1725 for (f = 0; f < Nf; ++f) { 1726 PetscCheckFalse(err[f] > tol,comm, PETSC_ERR_ARG_WRONG, "L_2 Error %g for field %D exceeds tolerance %g", (double) err[f], f, (double) tol); 1727 } 1728 } else if (error) { 1729 for (f = 0; f < Nf; ++f) error[f] = err[f]; 1730 } else { 1731 CHKERRQ(PetscPrintf(comm, "L_2 Error: [")); 1732 for (f = 0; f < Nf; ++f) { 1733 if (f) CHKERRQ(PetscPrintf(comm, ", ")); 1734 CHKERRQ(PetscPrintf(comm, "%g", (double)err[f])); 1735 } 1736 CHKERRQ(PetscPrintf(comm, "]\n")); 1737 } 1738 } else { 1739 CHKERRQ(DMComputeL2Diff(dm, t, exacts, ectxs, u, &err[0])); 1740 if (tol >= 0.0) { 1741 PetscCheckFalse(err[0] > tol,comm, PETSC_ERR_ARG_WRONG, "L_2 Error %g exceeds tolerance %g", (double) err[0], (double) tol); 1742 } else if (error) { 1743 error[0] = err[0]; 1744 } else { 1745 CHKERRQ(PetscPrintf(comm, "L_2 Error: %g\n", (double) err[0])); 1746 } 1747 } 1748 CHKERRQ(PetscFree3(exacts, ectxs, err)); 1749 PetscFunctionReturn(0); 1750 } 1751 1752 /*@C 1753 DMSNESCheckResidual - Check the residual of the exact solution 1754 1755 Input Parameters: 1756 + snes - the SNES object 1757 . dm - the DM 1758 . u - a DM vector 1759 - tol - A tolerance for the check, or -1 to print the results instead 1760 1761 Output Parameters: 1762 . residual - The residual norm of the exact solution, or NULL 1763 1764 Level: developer 1765 1766 .seealso: DNSNESCheckFromOptions(), DMSNESCheckDiscretization(), DMSNESCheckJacobian() 1767 @*/ 1768 PetscErrorCode DMSNESCheckResidual(SNES snes, DM dm, Vec u, PetscReal tol, PetscReal *residual) 1769 { 1770 MPI_Comm comm; 1771 Vec r; 1772 PetscReal res; 1773 1774 PetscFunctionBegin; 1775 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1); 1776 PetscValidHeaderSpecific(dm, DM_CLASSID, 2); 1777 PetscValidHeaderSpecific(u, VEC_CLASSID, 3); 1778 if (residual) PetscValidRealPointer(residual, 5); 1779 CHKERRQ(PetscObjectGetComm((PetscObject) snes, &comm)); 1780 CHKERRQ(DMComputeExactSolution(dm, 0.0, u, NULL)); 1781 CHKERRQ(VecDuplicate(u, &r)); 1782 CHKERRQ(SNESComputeFunction(snes, u, r)); 1783 CHKERRQ(VecNorm(r, NORM_2, &res)); 1784 if (tol >= 0.0) { 1785 PetscCheckFalse(res > tol,comm, PETSC_ERR_ARG_WRONG, "L_2 Residual %g exceeds tolerance %g", (double) res, (double) tol); 1786 } else if (residual) { 1787 *residual = res; 1788 } else { 1789 CHKERRQ(PetscPrintf(comm, "L_2 Residual: %g\n", (double)res)); 1790 CHKERRQ(VecChop(r, 1.0e-10)); 1791 CHKERRQ(PetscObjectSetName((PetscObject) r, "Initial Residual")); 1792 CHKERRQ(PetscObjectSetOptionsPrefix((PetscObject)r,"res_")); 1793 CHKERRQ(VecViewFromOptions(r, NULL, "-vec_view")); 1794 } 1795 CHKERRQ(VecDestroy(&r)); 1796 PetscFunctionReturn(0); 1797 } 1798 1799 /*@C 1800 DMSNESCheckJacobian - Check the Jacobian of the exact solution against the residual using the Taylor Test 1801 1802 Input Parameters: 1803 + snes - the SNES object 1804 . dm - the DM 1805 . u - a DM vector 1806 - tol - A tolerance for the check, or -1 to print the results instead 1807 1808 Output Parameters: 1809 + isLinear - Flag indicaing that the function looks linear, or NULL 1810 - convRate - The rate of convergence of the linear model, or NULL 1811 1812 Level: developer 1813 1814 .seealso: DNSNESCheckFromOptions(), DMSNESCheckDiscretization(), DMSNESCheckResidual() 1815 @*/ 1816 PetscErrorCode DMSNESCheckJacobian(SNES snes, DM dm, Vec u, PetscReal tol, PetscBool *isLinear, PetscReal *convRate) 1817 { 1818 MPI_Comm comm; 1819 PetscDS ds; 1820 Mat J, M; 1821 MatNullSpace nullspace; 1822 PetscReal slope, intercept; 1823 PetscBool hasJac, hasPrec, isLin = PETSC_FALSE; 1824 1825 PetscFunctionBegin; 1826 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1); 1827 PetscValidHeaderSpecific(dm, DM_CLASSID, 2); 1828 PetscValidHeaderSpecific(u, VEC_CLASSID, 3); 1829 if (isLinear) PetscValidBoolPointer(isLinear, 5); 1830 if (convRate) PetscValidRealPointer(convRate, 6); 1831 CHKERRQ(PetscObjectGetComm((PetscObject) snes, &comm)); 1832 CHKERRQ(DMComputeExactSolution(dm, 0.0, u, NULL)); 1833 /* Create and view matrices */ 1834 CHKERRQ(DMCreateMatrix(dm, &J)); 1835 CHKERRQ(DMGetDS(dm, &ds)); 1836 CHKERRQ(PetscDSHasJacobian(ds, &hasJac)); 1837 CHKERRQ(PetscDSHasJacobianPreconditioner(ds, &hasPrec)); 1838 if (hasJac && hasPrec) { 1839 CHKERRQ(DMCreateMatrix(dm, &M)); 1840 CHKERRQ(SNESComputeJacobian(snes, u, J, M)); 1841 CHKERRQ(PetscObjectSetName((PetscObject) M, "Preconditioning Matrix")); 1842 CHKERRQ(PetscObjectSetOptionsPrefix((PetscObject) M, "jacpre_")); 1843 CHKERRQ(MatViewFromOptions(M, NULL, "-mat_view")); 1844 CHKERRQ(MatDestroy(&M)); 1845 } else { 1846 CHKERRQ(SNESComputeJacobian(snes, u, J, J)); 1847 } 1848 CHKERRQ(PetscObjectSetName((PetscObject) J, "Jacobian")); 1849 CHKERRQ(PetscObjectSetOptionsPrefix((PetscObject) J, "jac_")); 1850 CHKERRQ(MatViewFromOptions(J, NULL, "-mat_view")); 1851 /* Check nullspace */ 1852 CHKERRQ(MatGetNullSpace(J, &nullspace)); 1853 if (nullspace) { 1854 PetscBool isNull; 1855 CHKERRQ(MatNullSpaceTest(nullspace, J, &isNull)); 1856 PetscCheckFalse(!isNull,comm, PETSC_ERR_PLIB, "The null space calculated for the system operator is invalid."); 1857 } 1858 /* Taylor test */ 1859 { 1860 PetscRandom rand; 1861 Vec du, uhat, r, rhat, df; 1862 PetscReal h; 1863 PetscReal *es, *hs, *errors; 1864 PetscReal hMax = 1.0, hMin = 1e-6, hMult = 0.1; 1865 PetscInt Nv, v; 1866 1867 /* Choose a perturbation direction */ 1868 CHKERRQ(PetscRandomCreate(comm, &rand)); 1869 CHKERRQ(VecDuplicate(u, &du)); 1870 CHKERRQ(VecSetRandom(du, rand)); 1871 CHKERRQ(PetscRandomDestroy(&rand)); 1872 CHKERRQ(VecDuplicate(u, &df)); 1873 CHKERRQ(MatMult(J, du, df)); 1874 /* Evaluate residual at u, F(u), save in vector r */ 1875 CHKERRQ(VecDuplicate(u, &r)); 1876 CHKERRQ(SNESComputeFunction(snes, u, r)); 1877 /* Look at the convergence of our Taylor approximation as we approach u */ 1878 for (h = hMax, Nv = 0; h >= hMin; h *= hMult, ++Nv); 1879 CHKERRQ(PetscCalloc3(Nv, &es, Nv, &hs, Nv, &errors)); 1880 CHKERRQ(VecDuplicate(u, &uhat)); 1881 CHKERRQ(VecDuplicate(u, &rhat)); 1882 for (h = hMax, Nv = 0; h >= hMin; h *= hMult, ++Nv) { 1883 CHKERRQ(VecWAXPY(uhat, h, du, u)); 1884 /* F(\hat u) \approx F(u) + J(u) (uhat - u) = F(u) + h * J(u) du */ 1885 CHKERRQ(SNESComputeFunction(snes, uhat, rhat)); 1886 CHKERRQ(VecAXPBYPCZ(rhat, -1.0, -h, 1.0, r, df)); 1887 CHKERRQ(VecNorm(rhat, NORM_2, &errors[Nv])); 1888 1889 es[Nv] = PetscLog10Real(errors[Nv]); 1890 hs[Nv] = PetscLog10Real(h); 1891 } 1892 CHKERRQ(VecDestroy(&uhat)); 1893 CHKERRQ(VecDestroy(&rhat)); 1894 CHKERRQ(VecDestroy(&df)); 1895 CHKERRQ(VecDestroy(&r)); 1896 CHKERRQ(VecDestroy(&du)); 1897 for (v = 0; v < Nv; ++v) { 1898 if ((tol >= 0) && (errors[v] > tol)) break; 1899 else if (errors[v] > PETSC_SMALL) break; 1900 } 1901 if (v == Nv) isLin = PETSC_TRUE; 1902 CHKERRQ(PetscLinearRegression(Nv, hs, es, &slope, &intercept)); 1903 CHKERRQ(PetscFree3(es, hs, errors)); 1904 /* Slope should be about 2 */ 1905 if (tol >= 0) { 1906 PetscCheckFalse(!isLin && PetscAbsReal(2 - slope) > tol,comm, PETSC_ERR_ARG_WRONG, "Taylor approximation convergence rate should be 2, not %0.2f", (double) slope); 1907 } else if (isLinear || convRate) { 1908 if (isLinear) *isLinear = isLin; 1909 if (convRate) *convRate = slope; 1910 } else { 1911 if (!isLin) CHKERRQ(PetscPrintf(comm, "Taylor approximation converging at order %3.2f\n", (double) slope)); 1912 else CHKERRQ(PetscPrintf(comm, "Function appears to be linear\n")); 1913 } 1914 } 1915 CHKERRQ(MatDestroy(&J)); 1916 PetscFunctionReturn(0); 1917 } 1918 1919 PetscErrorCode DMSNESCheck_Internal(SNES snes, DM dm, Vec u) 1920 { 1921 PetscFunctionBegin; 1922 CHKERRQ(DMSNESCheckDiscretization(snes, dm, 0.0, u, -1.0, NULL)); 1923 CHKERRQ(DMSNESCheckResidual(snes, dm, u, -1.0, NULL)); 1924 CHKERRQ(DMSNESCheckJacobian(snes, dm, u, -1.0, NULL, NULL)); 1925 PetscFunctionReturn(0); 1926 } 1927 1928 /*@C 1929 DMSNESCheckFromOptions - Check the residual and Jacobian functions using the exact solution by outputting some diagnostic information 1930 1931 Input Parameters: 1932 + snes - the SNES object 1933 - u - representative SNES vector 1934 1935 Note: The user must call PetscDSSetExactSolution() beforehand 1936 1937 Level: developer 1938 @*/ 1939 PetscErrorCode DMSNESCheckFromOptions(SNES snes, Vec u) 1940 { 1941 DM dm; 1942 Vec sol; 1943 PetscBool check; 1944 1945 PetscFunctionBegin; 1946 CHKERRQ(PetscOptionsHasName(((PetscObject)snes)->options,((PetscObject)snes)->prefix, "-dmsnes_check", &check)); 1947 if (!check) PetscFunctionReturn(0); 1948 CHKERRQ(SNESGetDM(snes, &dm)); 1949 CHKERRQ(VecDuplicate(u, &sol)); 1950 CHKERRQ(SNESSetSolution(snes, sol)); 1951 CHKERRQ(DMSNESCheck_Internal(snes, dm, sol)); 1952 CHKERRQ(VecDestroy(&sol)); 1953 PetscFunctionReturn(0); 1954 } 1955