1 #include <petscconvest.h> /*I "petscconvest.h" I*/ 2 #include <petscdmplex.h> 3 #include <petscds.h> 4 5 #include <petsc/private/petscconvestimpl.h> 6 7 static PetscErrorCode zero_private(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx) 8 { 9 PetscInt c; 10 for (c = 0; c < Nc; ++c) u[c] = 0.0; 11 return 0; 12 } 13 14 /*@ 15 PetscConvEstDestroy - Destroys a PetscConvEst object 16 17 Collective on PetscConvEst 18 19 Input Parameter: 20 . ce - The PetscConvEst object 21 22 Level: beginner 23 24 .seealso: PetscConvEstCreate(), PetscConvEstGetConvRate() 25 @*/ 26 PetscErrorCode PetscConvEstDestroy(PetscConvEst *ce) 27 { 28 PetscFunctionBegin; 29 if (!*ce) PetscFunctionReturn(0); 30 PetscValidHeaderSpecific((*ce),PETSC_OBJECT_CLASSID,1); 31 if (--((PetscObject)(*ce))->refct > 0) { 32 *ce = NULL; 33 PetscFunctionReturn(0); 34 } 35 PetscCall(PetscFree3((*ce)->initGuess, (*ce)->exactSol, (*ce)->ctxs)); 36 PetscCall(PetscFree2((*ce)->dofs, (*ce)->errors)); 37 PetscCall(PetscHeaderDestroy(ce)); 38 PetscFunctionReturn(0); 39 } 40 41 /*@ 42 PetscConvEstSetFromOptions - Sets a PetscConvEst object from options 43 44 Collective on PetscConvEst 45 46 Input Parameters: 47 . ce - The PetscConvEst object 48 49 Level: beginner 50 51 .seealso: PetscConvEstCreate(), PetscConvEstGetConvRate() 52 @*/ 53 PetscErrorCode PetscConvEstSetFromOptions(PetscConvEst ce) 54 { 55 PetscErrorCode ierr; 56 57 PetscFunctionBegin; 58 ierr = PetscOptionsBegin(PetscObjectComm((PetscObject) ce), "", "Convergence Estimator Options", "PetscConvEst");PetscCall(ierr); 59 PetscCall(PetscOptionsInt("-convest_num_refine", "The number of refinements for the convergence check", "PetscConvEst", ce->Nr, &ce->Nr, NULL)); 60 PetscCall(PetscOptionsReal("-convest_refine_factor", "The increase in resolution in each dimension", "PetscConvEst", ce->r, &ce->r, NULL)); 61 PetscCall(PetscOptionsBool("-convest_monitor", "Monitor the error for each convergence check", "PetscConvEst", ce->monitor, &ce->monitor, NULL)); 62 PetscCall(PetscOptionsBool("-convest_no_refine", "Debugging flag to run on the same mesh each time", "PetscConvEst", ce->noRefine, &ce->noRefine, NULL)); 63 ierr = PetscOptionsEnd();PetscCall(ierr); 64 PetscFunctionReturn(0); 65 } 66 67 /*@ 68 PetscConvEstView - Views a PetscConvEst object 69 70 Collective on PetscConvEst 71 72 Input Parameters: 73 + ce - The PetscConvEst object 74 - viewer - The PetscViewer object 75 76 Level: beginner 77 78 .seealso: PetscConvEstCreate(), PetscConvEstGetConvRate() 79 @*/ 80 PetscErrorCode PetscConvEstView(PetscConvEst ce, PetscViewer viewer) 81 { 82 PetscFunctionBegin; 83 PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject) ce, viewer)); 84 PetscCall(PetscViewerASCIIPrintf(viewer, "ConvEst with %D levels\n", ce->Nr+1)); 85 PetscFunctionReturn(0); 86 } 87 88 /*@ 89 PetscConvEstGetSolver - Gets the solver used to produce discrete solutions 90 91 Not collective 92 93 Input Parameter: 94 . ce - The PetscConvEst object 95 96 Output Parameter: 97 . solver - The solver 98 99 Level: intermediate 100 101 .seealso: PetscConvEstSetSolver(), PetscConvEstCreate(), PetscConvEstGetConvRate() 102 @*/ 103 PetscErrorCode PetscConvEstGetSolver(PetscConvEst ce, PetscObject *solver) 104 { 105 PetscFunctionBegin; 106 PetscValidHeaderSpecific(ce, PETSC_OBJECT_CLASSID, 1); 107 PetscValidPointer(solver, 2); 108 *solver = ce->solver; 109 PetscFunctionReturn(0); 110 } 111 112 /*@ 113 PetscConvEstSetSolver - Sets the solver used to produce discrete solutions 114 115 Not collective 116 117 Input Parameters: 118 + ce - The PetscConvEst object 119 - solver - The solver 120 121 Level: intermediate 122 123 Note: The solver MUST have an attached DM/DS, so that we know the exact solution 124 125 .seealso: PetscConvEstGetSNES(), PetscConvEstCreate(), PetscConvEstGetConvRate() 126 @*/ 127 PetscErrorCode PetscConvEstSetSolver(PetscConvEst ce, PetscObject solver) 128 { 129 PetscFunctionBegin; 130 PetscValidHeaderSpecific(ce, PETSC_OBJECT_CLASSID, 1); 131 PetscValidHeader(solver, 2); 132 ce->solver = solver; 133 PetscCall((*ce->ops->setsolver)(ce, solver)); 134 PetscFunctionReturn(0); 135 } 136 137 /*@ 138 PetscConvEstSetUp - After the solver is specified, we create structures for estimating convergence 139 140 Collective on PetscConvEst 141 142 Input Parameters: 143 . ce - The PetscConvEst object 144 145 Level: beginner 146 147 .seealso: PetscConvEstCreate(), PetscConvEstGetConvRate() 148 @*/ 149 PetscErrorCode PetscConvEstSetUp(PetscConvEst ce) 150 { 151 PetscInt Nf, f, Nds, s; 152 153 PetscFunctionBegin; 154 PetscCall(DMGetNumFields(ce->idm, &Nf)); 155 ce->Nf = PetscMax(Nf, 1); 156 PetscCall(PetscMalloc2((ce->Nr+1)*ce->Nf, &ce->dofs, (ce->Nr+1)*ce->Nf, &ce->errors)); 157 PetscCall(PetscCalloc3(ce->Nf, &ce->initGuess, ce->Nf, &ce->exactSol, ce->Nf, &ce->ctxs)); 158 for (f = 0; f < Nf; ++f) ce->initGuess[f] = zero_private; 159 PetscCall(DMGetNumDS(ce->idm, &Nds)); 160 for (s = 0; s < Nds; ++s) { 161 PetscDS ds; 162 DMLabel label; 163 IS fieldIS; 164 const PetscInt *fields; 165 PetscInt dsNf; 166 167 PetscCall(DMGetRegionNumDS(ce->idm, s, &label, &fieldIS, &ds)); 168 PetscCall(PetscDSGetNumFields(ds, &dsNf)); 169 if (fieldIS) PetscCall(ISGetIndices(fieldIS, &fields)); 170 for (f = 0; f < dsNf; ++f) { 171 const PetscInt field = fields[f]; 172 PetscCall(PetscDSGetExactSolution(ds, field, &ce->exactSol[field], &ce->ctxs[field])); 173 } 174 if (fieldIS) PetscCall(ISRestoreIndices(fieldIS, &fields)); 175 } 176 for (f = 0; f < Nf; ++f) { 177 PetscCheckFalse(!ce->exactSol[f],PetscObjectComm((PetscObject) ce), PETSC_ERR_ARG_WRONG, "DS must contain exact solution functions in order to estimate convergence, missing for field %D", f); 178 } 179 PetscFunctionReturn(0); 180 } 181 182 PetscErrorCode PetscConvEstComputeInitialGuess(PetscConvEst ce, PetscInt r, DM dm, Vec u) 183 { 184 PetscFunctionBegin; 185 PetscValidHeaderSpecific(ce, PETSC_OBJECT_CLASSID, 1); 186 if (dm) PetscValidHeaderSpecific(dm, DM_CLASSID, 3); 187 PetscValidHeaderSpecific(u, VEC_CLASSID, 4); 188 PetscCall((*ce->ops->initguess)(ce, r, dm, u)); 189 PetscFunctionReturn(0); 190 } 191 192 PetscErrorCode PetscConvEstComputeError(PetscConvEst ce, PetscInt r, DM dm, Vec u, PetscReal errors[]) 193 { 194 PetscFunctionBegin; 195 PetscValidHeaderSpecific(ce, PETSC_OBJECT_CLASSID, 1); 196 if (dm) PetscValidHeaderSpecific(dm, DM_CLASSID, 3); 197 PetscValidHeaderSpecific(u, VEC_CLASSID, 4); 198 PetscValidRealPointer(errors, 5); 199 PetscCall((*ce->ops->computeerror)(ce, r, dm, u, errors)); 200 PetscFunctionReturn(0); 201 } 202 203 /*@ 204 PetscConvEstMonitorDefault - Monitors the convergence estimation loop 205 206 Collective on PetscConvEst 207 208 Input Parameters: 209 + ce - The PetscConvEst object 210 - r - The refinement level 211 212 Options database keys: 213 . -convest_monitor - Activate the monitor 214 215 Level: intermediate 216 217 .seealso: PetscConvEstCreate(), PetscConvEstGetConvRate(), SNESSolve(), TSSolve() 218 @*/ 219 PetscErrorCode PetscConvEstMonitorDefault(PetscConvEst ce, PetscInt r) 220 { 221 MPI_Comm comm; 222 PetscInt f; 223 224 PetscFunctionBegin; 225 if (ce->monitor) { 226 PetscInt *dofs = &ce->dofs[r*ce->Nf]; 227 PetscReal *errors = &ce->errors[r*ce->Nf]; 228 229 PetscCall(PetscObjectGetComm((PetscObject) ce, &comm)); 230 PetscCall(PetscPrintf(comm, "N: ")); 231 if (ce->Nf > 1) PetscCall(PetscPrintf(comm, "[")); 232 for (f = 0; f < ce->Nf; ++f) { 233 if (f > 0) PetscCall(PetscPrintf(comm, ", ")); 234 PetscCall(PetscPrintf(comm, "%7D", dofs[f])); 235 } 236 if (ce->Nf > 1) PetscCall(PetscPrintf(comm, "]")); 237 PetscCall(PetscPrintf(comm, " ")); 238 PetscCall(PetscPrintf(comm, "L_2 Error: ")); 239 if (ce->Nf > 1) PetscCall(PetscPrintf(comm, "[")); 240 for (f = 0; f < ce->Nf; ++f) { 241 if (f > 0) PetscCall(PetscPrintf(comm, ", ")); 242 if (errors[f] < 1.0e-11) PetscCall(PetscPrintf(comm, "< 1e-11")); 243 else PetscCall(PetscPrintf(comm, "%g", (double) errors[f])); 244 } 245 if (ce->Nf > 1) PetscCall(PetscPrintf(comm, "]")); 246 PetscCall(PetscPrintf(comm, "\n")); 247 } 248 PetscFunctionReturn(0); 249 } 250 251 static PetscErrorCode PetscConvEstSetSNES_Private(PetscConvEst ce, PetscObject solver) 252 { 253 PetscClassId id; 254 255 PetscFunctionBegin; 256 PetscCall(PetscObjectGetClassId(ce->solver, &id)); 257 PetscCheckFalse(id != SNES_CLASSID,PetscObjectComm((PetscObject) ce), PETSC_ERR_ARG_WRONG, "Solver was not a SNES"); 258 PetscCall(SNESGetDM((SNES) ce->solver, &ce->idm)); 259 PetscFunctionReturn(0); 260 } 261 262 static PetscErrorCode PetscConvEstInitGuessSNES_Private(PetscConvEst ce, PetscInt r, DM dm, Vec u) 263 { 264 PetscFunctionBegin; 265 PetscCall(DMProjectFunction(dm, 0.0, ce->initGuess, ce->ctxs, INSERT_VALUES, u)); 266 PetscFunctionReturn(0); 267 } 268 269 static PetscErrorCode PetscConvEstComputeErrorSNES_Private(PetscConvEst ce, PetscInt r, DM dm, Vec u, PetscReal errors[]) 270 { 271 PetscFunctionBegin; 272 PetscCall(DMComputeL2FieldDiff(dm, 0.0, ce->exactSol, ce->ctxs, u, errors)); 273 PetscFunctionReturn(0); 274 } 275 276 static PetscErrorCode PetscConvEstSetJacobianNullspace_Private(PetscConvEst ce, SNES snes) 277 { 278 DM dm; 279 PetscInt f; 280 281 PetscFunctionBegin; 282 PetscCall(SNESGetDM(snes, &dm)); 283 for (f = 0; f < ce->Nf; ++f) { 284 PetscErrorCode (*nspconstr)(DM, PetscInt, PetscInt, MatNullSpace *); 285 286 PetscCall(DMGetNullSpaceConstructor(dm, f, &nspconstr)); 287 if (nspconstr) { 288 MatNullSpace nullsp; 289 Mat J; 290 291 PetscCall((*nspconstr)(dm, f, f,&nullsp)); 292 PetscCall(SNESSetUp(snes)); 293 PetscCall(SNESGetJacobian(snes, &J, NULL, NULL, NULL)); 294 PetscCall(MatSetNullSpace(J, nullsp)); 295 PetscCall(MatNullSpaceDestroy(&nullsp)); 296 break; 297 } 298 } 299 PetscFunctionReturn(0); 300 } 301 302 static PetscErrorCode PetscConvEstGetConvRateSNES_Private(PetscConvEst ce, PetscReal alpha[]) 303 { 304 SNES snes = (SNES) ce->solver; 305 DM *dm; 306 PetscObject disc; 307 PetscReal *x, *y, slope, intercept; 308 PetscInt Nr = ce->Nr, r, f, dim, oldlevel, oldnlev; 309 void *ctx; 310 311 PetscFunctionBegin; 312 PetscCheckFalse(ce->r != 2.0,PetscObjectComm((PetscObject) ce), PETSC_ERR_SUP, "Only refinement factor 2 is currently supported (not %g)", (double) ce->r); 313 PetscCall(DMGetDimension(ce->idm, &dim)); 314 PetscCall(DMGetApplicationContext(ce->idm, &ctx)); 315 PetscCall(DMPlexSetRefinementUniform(ce->idm, PETSC_TRUE)); 316 PetscCall(DMGetRefineLevel(ce->idm, &oldlevel)); 317 PetscCall(PetscMalloc1((Nr+1), &dm)); 318 /* Loop over meshes */ 319 dm[0] = ce->idm; 320 for (r = 0; r <= Nr; ++r) { 321 Vec u; 322 #if defined(PETSC_USE_LOG) 323 PetscLogStage stage; 324 #endif 325 char stageName[PETSC_MAX_PATH_LEN]; 326 const char *dmname, *uname; 327 328 PetscCall(PetscSNPrintf(stageName, PETSC_MAX_PATH_LEN-1, "ConvEst Refinement Level %D", r)); 329 #if defined(PETSC_USE_LOG) 330 PetscCall(PetscLogStageGetId(stageName, &stage)); 331 if (stage < 0) PetscCall(PetscLogStageRegister(stageName, &stage)); 332 #endif 333 PetscCall(PetscLogStagePush(stage)); 334 if (r > 0) { 335 if (!ce->noRefine) { 336 PetscCall(DMRefine(dm[r-1], MPI_COMM_NULL, &dm[r])); 337 PetscCall(DMSetCoarseDM(dm[r], dm[r-1])); 338 } else { 339 DM cdm, rcdm; 340 341 PetscCall(DMClone(dm[r-1], &dm[r])); 342 PetscCall(DMCopyDisc(dm[r-1], dm[r])); 343 PetscCall(DMGetCoordinateDM(dm[r-1], &cdm)); 344 PetscCall(DMGetCoordinateDM(dm[r], &rcdm)); 345 PetscCall(DMCopyDisc(cdm, rcdm)); 346 } 347 PetscCall(DMCopyTransform(ce->idm, dm[r])); 348 PetscCall(PetscObjectGetName((PetscObject) dm[r-1], &dmname)); 349 PetscCall(PetscObjectSetName((PetscObject) dm[r], dmname)); 350 for (f = 0; f < ce->Nf; ++f) { 351 PetscErrorCode (*nspconstr)(DM, PetscInt, PetscInt, MatNullSpace *); 352 353 PetscCall(DMGetNullSpaceConstructor(dm[r-1], f, &nspconstr)); 354 PetscCall(DMSetNullSpaceConstructor(dm[r], f, nspconstr)); 355 } 356 } 357 PetscCall(DMViewFromOptions(dm[r], NULL, "-conv_dm_view")); 358 /* Create solution */ 359 PetscCall(DMCreateGlobalVector(dm[r], &u)); 360 PetscCall(DMGetField(dm[r], 0, NULL, &disc)); 361 PetscCall(PetscObjectGetName(disc, &uname)); 362 PetscCall(PetscObjectSetName((PetscObject) u, uname)); 363 /* Setup solver */ 364 PetscCall(SNESReset(snes)); 365 PetscCall(SNESSetDM(snes, dm[r])); 366 PetscCall(DMPlexSetSNESLocalFEM(dm[r], ctx, ctx, ctx)); 367 PetscCall(SNESSetFromOptions(snes)); 368 /* Set nullspace for Jacobian */ 369 PetscCall(PetscConvEstSetJacobianNullspace_Private(ce, snes)); 370 /* Create initial guess */ 371 PetscCall(PetscConvEstComputeInitialGuess(ce, r, dm[r], u)); 372 PetscCall(SNESSolve(snes, NULL, u)); 373 PetscCall(PetscLogEventBegin(ce->event, ce, 0, 0, 0)); 374 PetscCall(PetscConvEstComputeError(ce, r, dm[r], u, &ce->errors[r*ce->Nf])); 375 PetscCall(PetscLogEventEnd(ce->event, ce, 0, 0, 0)); 376 for (f = 0; f < ce->Nf; ++f) { 377 PetscSection s, fs; 378 PetscInt lsize; 379 380 /* Could use DMGetOutputDM() to add in Dirichlet dofs */ 381 PetscCall(DMGetLocalSection(dm[r], &s)); 382 PetscCall(PetscSectionGetField(s, f, &fs)); 383 PetscCall(PetscSectionGetConstrainedStorageSize(fs, &lsize)); 384 PetscCallMPI(MPI_Allreduce(&lsize, &ce->dofs[r*ce->Nf+f], 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject) snes))); 385 PetscCall(PetscLogEventSetDof(ce->event, f, ce->dofs[r*ce->Nf+f])); 386 PetscCall(PetscLogEventSetError(ce->event, f, ce->errors[r*ce->Nf+f])); 387 } 388 /* Monitor */ 389 PetscCall(PetscConvEstMonitorDefault(ce, r)); 390 if (!r) { 391 /* PCReset() does not wipe out the level structure */ 392 KSP ksp; 393 PC pc; 394 395 PetscCall(SNESGetKSP(snes, &ksp)); 396 PetscCall(KSPGetPC(ksp, &pc)); 397 PetscCall(PCMGGetLevels(pc, &oldnlev)); 398 } 399 /* Cleanup */ 400 PetscCall(VecDestroy(&u)); 401 PetscCall(PetscLogStagePop()); 402 } 403 for (r = 1; r <= Nr; ++r) { 404 PetscCall(DMDestroy(&dm[r])); 405 } 406 /* Fit convergence rate */ 407 PetscCall(PetscMalloc2(Nr+1, &x, Nr+1, &y)); 408 for (f = 0; f < ce->Nf; ++f) { 409 for (r = 0; r <= Nr; ++r) { 410 x[r] = PetscLog10Real(ce->dofs[r*ce->Nf+f]); 411 y[r] = PetscLog10Real(ce->errors[r*ce->Nf+f]); 412 } 413 PetscCall(PetscLinearRegression(Nr+1, x, y, &slope, &intercept)); 414 /* Since h^{-dim} = N, lg err = s lg N + b = -s dim lg h + b */ 415 alpha[f] = -slope * dim; 416 } 417 PetscCall(PetscFree2(x, y)); 418 PetscCall(PetscFree(dm)); 419 /* Restore solver */ 420 PetscCall(SNESReset(snes)); 421 { 422 /* PCReset() does not wipe out the level structure */ 423 KSP ksp; 424 PC pc; 425 426 PetscCall(SNESGetKSP(snes, &ksp)); 427 PetscCall(KSPGetPC(ksp, &pc)); 428 PetscCall(PCMGSetLevels(pc, oldnlev, NULL)); 429 PetscCall(DMSetRefineLevel(ce->idm, oldlevel)); /* The damn DMCoarsen() calls in PCMG can reset this */ 430 } 431 PetscCall(SNESSetDM(snes, ce->idm)); 432 PetscCall(DMPlexSetSNESLocalFEM(ce->idm, ctx, ctx, ctx)); 433 PetscCall(SNESSetFromOptions(snes)); 434 PetscCall(PetscConvEstSetJacobianNullspace_Private(ce, snes)); 435 PetscFunctionReturn(0); 436 } 437 438 /*@ 439 PetscConvEstGetConvRate - Returns an estimate of the convergence rate for the discretization 440 441 Not collective 442 443 Input Parameter: 444 . ce - The PetscConvEst object 445 446 Output Parameter: 447 . alpha - The convergence rate for each field 448 449 Note: The convergence rate alpha is defined by 450 $ || u_\Delta - u_exact || < C \Delta^alpha 451 where u_\Delta is the discrete solution, and Delta is a measure of the discretization size. We usually use h for the 452 spatial resolution and \Delta t for the temporal resolution. 453 454 We solve a series of problems using increasing resolution (refined meshes or decreased timesteps), calculate an error 455 based upon the exact solution in the DS, and then fit the result to our model above using linear regression. 456 457 Options database keys: 458 + -snes_convergence_estimate - Execute convergence estimation inside SNESSolve() and print out the rate 459 - -ts_convergence_estimate - Execute convergence estimation inside TSSolve() and print out the rate 460 461 Level: intermediate 462 463 .seealso: PetscConvEstSetSolver(), PetscConvEstCreate(), PetscConvEstGetConvRate(), SNESSolve(), TSSolve() 464 @*/ 465 PetscErrorCode PetscConvEstGetConvRate(PetscConvEst ce, PetscReal alpha[]) 466 { 467 PetscInt f; 468 469 PetscFunctionBegin; 470 if (ce->event < 0) PetscCall(PetscLogEventRegister("ConvEst Error", PETSC_OBJECT_CLASSID, &ce->event)); 471 for (f = 0; f < ce->Nf; ++f) alpha[f] = 0.0; 472 PetscCall((*ce->ops->getconvrate)(ce, alpha)); 473 PetscFunctionReturn(0); 474 } 475 476 /*@ 477 PetscConvEstRateView - Displays the convergence rate to a viewer 478 479 Collective on SNES 480 481 Parameter: 482 + snes - iterative context obtained from SNESCreate() 483 . alpha - the convergence rate for each field 484 - viewer - the viewer to display the reason 485 486 Options Database Keys: 487 . -snes_convergence_estimate - print the convergence rate 488 489 Level: developer 490 491 .seealso: PetscConvEstGetRate() 492 @*/ 493 PetscErrorCode PetscConvEstRateView(PetscConvEst ce, const PetscReal alpha[], PetscViewer viewer) 494 { 495 PetscBool isAscii; 496 497 PetscFunctionBegin; 498 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &isAscii)); 499 if (isAscii) { 500 PetscInt Nf = ce->Nf, f; 501 502 PetscCall(PetscViewerASCIIAddTab(viewer, ((PetscObject) ce)->tablevel)); 503 PetscCall(PetscViewerASCIIPrintf(viewer, "L_2 convergence rate: ")); 504 if (Nf > 1) PetscCall(PetscViewerASCIIPrintf(viewer, "[")); 505 for (f = 0; f < Nf; ++f) { 506 if (f > 0) PetscCall(PetscViewerASCIIPrintf(viewer, ", ")); 507 PetscCall(PetscViewerASCIIPrintf(viewer, "%#.2g", (double) alpha[f])); 508 } 509 if (Nf > 1) PetscCall(PetscViewerASCIIPrintf(viewer, "]")); 510 PetscCall(PetscViewerASCIIPrintf(viewer, "\n")); 511 PetscCall(PetscViewerASCIISubtractTab(viewer, ((PetscObject) ce)->tablevel)); 512 } 513 PetscFunctionReturn(0); 514 } 515 516 /*@ 517 PetscConvEstCreate - Create a PetscConvEst object 518 519 Collective 520 521 Input Parameter: 522 . comm - The communicator for the PetscConvEst object 523 524 Output Parameter: 525 . ce - The PetscConvEst object 526 527 Level: beginner 528 529 .seealso: PetscConvEstDestroy(), PetscConvEstGetConvRate() 530 @*/ 531 PetscErrorCode PetscConvEstCreate(MPI_Comm comm, PetscConvEst *ce) 532 { 533 PetscFunctionBegin; 534 PetscValidPointer(ce, 2); 535 PetscCall(PetscSysInitializePackage()); 536 PetscCall(PetscHeaderCreate(*ce, PETSC_OBJECT_CLASSID, "PetscConvEst", "ConvergenceEstimator", "SNES", comm, PetscConvEstDestroy, PetscConvEstView)); 537 (*ce)->monitor = PETSC_FALSE; 538 (*ce)->r = 2.0; 539 (*ce)->Nr = 4; 540 (*ce)->event = -1; 541 (*ce)->ops->setsolver = PetscConvEstSetSNES_Private; 542 (*ce)->ops->initguess = PetscConvEstInitGuessSNES_Private; 543 (*ce)->ops->computeerror = PetscConvEstComputeErrorSNES_Private; 544 (*ce)->ops->getconvrate = PetscConvEstGetConvRateSNES_Private; 545 PetscFunctionReturn(0); 546 } 547