Actual source code: posindep.c
1: /*
2: Code for Timestepping with implicit backwards Euler.
3: */
4: #include <petsc/private/tsimpl.h>
6: typedef struct {
7: Vec update; /* work vector where new solution is formed */
8: Vec func; /* work vector where F(t[i],u[i]) is stored */
9: Vec xdot; /* work vector for time derivative of state */
11: /* information used for Pseudo-timestepping */
13: PetscErrorCode (*dt)(TS, PetscReal *, void *); /* compute next timestep, and related context */
14: void *dtctx;
15: PetscErrorCode (*verify)(TS, Vec, void *, PetscReal *, PetscBool *); /* verify previous timestep and related context */
16: void *verifyctx;
18: PetscReal fnorm_initial, fnorm; /* original and current norm of F(u) */
19: PetscReal fnorm_previous;
21: PetscReal dt_initial; /* initial time-step */
22: PetscReal dt_increment; /* scaling that dt is incremented each time-step */
23: PetscReal dt_max; /* maximum time step */
24: PetscBool increment_dt_from_initial_dt;
25: PetscReal fatol, frtol;
26: } TS_Pseudo;
28: /* ------------------------------------------------------------------------------*/
30: /*@C
31: TSPseudoComputeTimeStep - Computes the next timestep for a currently running
32: pseudo-timestepping process.
34: Collective
36: Input Parameter:
37: . ts - timestep context
39: Output Parameter:
40: . dt - newly computed timestep
42: Level: developer
44: Note:
45: The routine to be called here to compute the timestep should be
46: set by calling `TSPseudoSetTimeStep()`.
48: .seealso: [](chapter_ts), `TSPSEUDO`, `TSPseudoTimeStepDefault()`, `TSPseudoSetTimeStep()`
49: @*/
50: PetscErrorCode TSPseudoComputeTimeStep(TS ts, PetscReal *dt)
51: {
52: TS_Pseudo *pseudo = (TS_Pseudo *)ts->data;
54: PetscFunctionBegin;
55: PetscCall(PetscLogEventBegin(TS_PseudoComputeTimeStep, ts, 0, 0, 0));
56: PetscCall((*pseudo->dt)(ts, dt, pseudo->dtctx));
57: PetscCall(PetscLogEventEnd(TS_PseudoComputeTimeStep, ts, 0, 0, 0));
58: PetscFunctionReturn(PETSC_SUCCESS);
59: }
61: /* ------------------------------------------------------------------------------*/
62: /*@C
63: TSPseudoVerifyTimeStepDefault - Default code to verify the quality of the last timestep.
65: Collective
67: Input Parameters:
68: + ts - the timestep context
69: . dtctx - unused timestep context
70: - update - latest solution vector
72: Output Parameters:
73: + newdt - the timestep to use for the next step
74: - flag - flag indicating whether the last time step was acceptable
76: Level: advanced
78: Note:
79: This routine always returns a flag of 1, indicating an acceptable
80: timestep.
82: .seealso: [](chapter_ts), `TSPSEUDO`, `TSPseudoSetVerifyTimeStep()`, `TSPseudoVerifyTimeStep()`
83: @*/
84: PetscErrorCode TSPseudoVerifyTimeStepDefault(TS ts, Vec update, void *dtctx, PetscReal *newdt, PetscBool *flag)
85: {
86: PetscFunctionBegin;
87: *flag = PETSC_TRUE;
88: PetscFunctionReturn(PETSC_SUCCESS);
89: }
91: /*@
92: TSPseudoVerifyTimeStep - Verifies whether the last timestep was acceptable.
94: Collective
96: Input Parameters:
97: + ts - timestep context
98: - update - latest solution vector
100: Output Parameters:
101: + dt - newly computed timestep (if it had to shrink)
102: - flag - indicates if current timestep was ok
104: Level: advanced
106: Notes:
107: The routine to be called here to compute the timestep should be
108: set by calling `TSPseudoSetVerifyTimeStep()`.
110: .seealso: [](chapter_ts), `TSPSEUDO`, `TSPseudoSetVerifyTimeStep()`, `TSPseudoVerifyTimeStepDefault()`
111: @*/
112: PetscErrorCode TSPseudoVerifyTimeStep(TS ts, Vec update, PetscReal *dt, PetscBool *flag)
113: {
114: TS_Pseudo *pseudo = (TS_Pseudo *)ts->data;
116: PetscFunctionBegin;
117: *flag = PETSC_TRUE;
118: if (pseudo->verify) PetscCall((*pseudo->verify)(ts, update, pseudo->verifyctx, dt, flag));
119: PetscFunctionReturn(PETSC_SUCCESS);
120: }
122: /* --------------------------------------------------------------------------------*/
124: static PetscErrorCode TSStep_Pseudo(TS ts)
125: {
126: TS_Pseudo *pseudo = (TS_Pseudo *)ts->data;
127: PetscInt nits, lits, reject;
128: PetscBool stepok;
129: PetscReal next_time_step = ts->time_step;
131: PetscFunctionBegin;
132: if (ts->steps == 0) pseudo->dt_initial = ts->time_step;
133: PetscCall(VecCopy(ts->vec_sol, pseudo->update));
134: PetscCall(TSPseudoComputeTimeStep(ts, &next_time_step));
135: for (reject = 0; reject < ts->max_reject; reject++, ts->reject++) {
136: ts->time_step = next_time_step;
137: PetscCall(TSPreStage(ts, ts->ptime + ts->time_step));
138: PetscCall(SNESSolve(ts->snes, NULL, pseudo->update));
139: PetscCall(SNESGetIterationNumber(ts->snes, &nits));
140: PetscCall(SNESGetLinearSolveIterations(ts->snes, &lits));
141: ts->snes_its += nits;
142: ts->ksp_its += lits;
143: PetscCall(TSPostStage(ts, ts->ptime + ts->time_step, 0, &(pseudo->update)));
144: PetscCall(TSAdaptCheckStage(ts->adapt, ts, ts->ptime + ts->time_step, pseudo->update, &stepok));
145: if (!stepok) {
146: next_time_step = ts->time_step;
147: continue;
148: }
149: pseudo->fnorm = -1; /* The current norm is no longer valid, monitor must recompute it. */
150: PetscCall(TSPseudoVerifyTimeStep(ts, pseudo->update, &next_time_step, &stepok));
151: if (stepok) break;
152: }
153: if (reject >= ts->max_reject) {
154: ts->reason = TS_DIVERGED_STEP_REJECTED;
155: PetscCall(PetscInfo(ts, "Step=%" PetscInt_FMT ", step rejections %" PetscInt_FMT " greater than current TS allowed, stopping solve\n", ts->steps, reject));
156: PetscFunctionReturn(PETSC_SUCCESS);
157: }
159: PetscCall(VecCopy(pseudo->update, ts->vec_sol));
160: ts->ptime += ts->time_step;
161: ts->time_step = next_time_step;
163: if (pseudo->fnorm < 0) {
164: PetscCall(VecZeroEntries(pseudo->xdot));
165: PetscCall(TSComputeIFunction(ts, ts->ptime, ts->vec_sol, pseudo->xdot, pseudo->func, PETSC_FALSE));
166: PetscCall(VecNorm(pseudo->func, NORM_2, &pseudo->fnorm));
167: }
168: if (pseudo->fnorm < pseudo->fatol) {
169: ts->reason = TS_CONVERGED_PSEUDO_FATOL;
170: PetscCall(PetscInfo(ts, "Step=%" PetscInt_FMT ", converged since fnorm %g < fatol %g\n", ts->steps, (double)pseudo->fnorm, (double)pseudo->frtol));
171: PetscFunctionReturn(PETSC_SUCCESS);
172: }
173: if (pseudo->fnorm / pseudo->fnorm_initial < pseudo->frtol) {
174: ts->reason = TS_CONVERGED_PSEUDO_FRTOL;
175: PetscCall(PetscInfo(ts, "Step=%" PetscInt_FMT ", converged since fnorm %g / fnorm_initial %g < frtol %g\n", ts->steps, (double)pseudo->fnorm, (double)pseudo->fnorm_initial, (double)pseudo->fatol));
176: PetscFunctionReturn(PETSC_SUCCESS);
177: }
178: PetscFunctionReturn(PETSC_SUCCESS);
179: }
181: /*------------------------------------------------------------*/
182: static PetscErrorCode TSReset_Pseudo(TS ts)
183: {
184: TS_Pseudo *pseudo = (TS_Pseudo *)ts->data;
186: PetscFunctionBegin;
187: PetscCall(VecDestroy(&pseudo->update));
188: PetscCall(VecDestroy(&pseudo->func));
189: PetscCall(VecDestroy(&pseudo->xdot));
190: PetscFunctionReturn(PETSC_SUCCESS);
191: }
193: static PetscErrorCode TSDestroy_Pseudo(TS ts)
194: {
195: PetscFunctionBegin;
196: PetscCall(TSReset_Pseudo(ts));
197: PetscCall(PetscFree(ts->data));
198: PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSPseudoSetVerifyTimeStep_C", NULL));
199: PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSPseudoSetTimeStepIncrement_C", NULL));
200: PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSPseudoSetMaxTimeStep_C", NULL));
201: PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSPseudoIncrementDtFromInitialDt_C", NULL));
202: PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSPseudoSetTimeStep_C", NULL));
203: PetscFunctionReturn(PETSC_SUCCESS);
204: }
206: /*------------------------------------------------------------*/
208: /*
209: Compute Xdot = (X^{n+1}-X^n)/dt) = 0
210: */
211: static PetscErrorCode TSPseudoGetXdot(TS ts, Vec X, Vec *Xdot)
212: {
213: TS_Pseudo *pseudo = (TS_Pseudo *)ts->data;
214: const PetscScalar mdt = 1.0 / ts->time_step, *xnp1, *xn;
215: PetscScalar *xdot;
216: PetscInt i, n;
218: PetscFunctionBegin;
219: *Xdot = NULL;
220: PetscCall(VecGetArrayRead(ts->vec_sol, &xn));
221: PetscCall(VecGetArrayRead(X, &xnp1));
222: PetscCall(VecGetArray(pseudo->xdot, &xdot));
223: PetscCall(VecGetLocalSize(X, &n));
224: for (i = 0; i < n; i++) xdot[i] = mdt * (xnp1[i] - xn[i]);
225: PetscCall(VecRestoreArrayRead(ts->vec_sol, &xn));
226: PetscCall(VecRestoreArrayRead(X, &xnp1));
227: PetscCall(VecRestoreArray(pseudo->xdot, &xdot));
228: *Xdot = pseudo->xdot;
229: PetscFunctionReturn(PETSC_SUCCESS);
230: }
232: /*
233: The transient residual is
235: F(U^{n+1},(U^{n+1}-U^n)/dt) = 0
237: or for ODE,
239: (U^{n+1} - U^{n})/dt - F(U^{n+1}) = 0
241: This is the function that must be evaluated for transient simulation and for
242: finite difference Jacobians. On the first Newton step, this algorithm uses
243: a guess of U^{n+1} = U^n in which case the transient term vanishes and the
244: residual is actually the steady state residual. Pseudotransient
245: continuation as described in the literature is a linearly implicit
246: algorithm, it only takes this one Newton step with the steady state
247: residual, and then advances to the next time step.
248: */
249: static PetscErrorCode SNESTSFormFunction_Pseudo(SNES snes, Vec X, Vec Y, TS ts)
250: {
251: Vec Xdot;
253: PetscFunctionBegin;
254: PetscCall(TSPseudoGetXdot(ts, X, &Xdot));
255: PetscCall(TSComputeIFunction(ts, ts->ptime + ts->time_step, X, Xdot, Y, PETSC_FALSE));
256: PetscFunctionReturn(PETSC_SUCCESS);
257: }
259: /*
260: This constructs the Jacobian needed for SNES. For DAE, this is
262: dF(X,Xdot)/dX + shift*dF(X,Xdot)/dXdot
264: and for ODE:
266: J = I/dt - J_{Frhs} where J_{Frhs} is the given Jacobian of Frhs.
267: */
268: static PetscErrorCode SNESTSFormJacobian_Pseudo(SNES snes, Vec X, Mat AA, Mat BB, TS ts)
269: {
270: Vec Xdot;
272: PetscFunctionBegin;
273: PetscCall(TSPseudoGetXdot(ts, X, &Xdot));
274: PetscCall(TSComputeIJacobian(ts, ts->ptime + ts->time_step, X, Xdot, 1. / ts->time_step, AA, BB, PETSC_FALSE));
275: PetscFunctionReturn(PETSC_SUCCESS);
276: }
278: static PetscErrorCode TSSetUp_Pseudo(TS ts)
279: {
280: TS_Pseudo *pseudo = (TS_Pseudo *)ts->data;
282: PetscFunctionBegin;
283: PetscCall(VecDuplicate(ts->vec_sol, &pseudo->update));
284: PetscCall(VecDuplicate(ts->vec_sol, &pseudo->func));
285: PetscCall(VecDuplicate(ts->vec_sol, &pseudo->xdot));
286: PetscFunctionReturn(PETSC_SUCCESS);
287: }
288: /*------------------------------------------------------------*/
290: static PetscErrorCode TSPseudoMonitorDefault(TS ts, PetscInt step, PetscReal ptime, Vec v, void *dummy)
291: {
292: TS_Pseudo *pseudo = (TS_Pseudo *)ts->data;
293: PetscViewer viewer = (PetscViewer)dummy;
295: PetscFunctionBegin;
296: if (pseudo->fnorm < 0) { /* The last computed norm is stale, recompute */
297: PetscCall(VecZeroEntries(pseudo->xdot));
298: PetscCall(TSComputeIFunction(ts, ts->ptime, ts->vec_sol, pseudo->xdot, pseudo->func, PETSC_FALSE));
299: PetscCall(VecNorm(pseudo->func, NORM_2, &pseudo->fnorm));
300: }
301: PetscCall(PetscViewerASCIIAddTab(viewer, ((PetscObject)ts)->tablevel));
302: PetscCall(PetscViewerASCIIPrintf(viewer, "TS %" PetscInt_FMT " dt %g time %g fnorm %g\n", step, (double)ts->time_step, (double)ptime, (double)pseudo->fnorm));
303: PetscCall(PetscViewerASCIISubtractTab(viewer, ((PetscObject)ts)->tablevel));
304: PetscFunctionReturn(PETSC_SUCCESS);
305: }
307: static PetscErrorCode TSSetFromOptions_Pseudo(TS ts, PetscOptionItems *PetscOptionsObject)
308: {
309: TS_Pseudo *pseudo = (TS_Pseudo *)ts->data;
310: PetscBool flg = PETSC_FALSE;
311: PetscViewer viewer;
313: PetscFunctionBegin;
314: PetscOptionsHeadBegin(PetscOptionsObject, "Pseudo-timestepping options");
315: PetscCall(PetscOptionsBool("-ts_monitor_pseudo", "Monitor convergence", "", flg, &flg, NULL));
316: if (flg) {
317: PetscCall(PetscViewerASCIIOpen(PetscObjectComm((PetscObject)ts), "stdout", &viewer));
318: PetscCall(TSMonitorSet(ts, TSPseudoMonitorDefault, viewer, (PetscErrorCode(*)(void **))PetscViewerDestroy));
319: }
320: flg = pseudo->increment_dt_from_initial_dt;
321: PetscCall(PetscOptionsBool("-ts_pseudo_increment_dt_from_initial_dt", "Increase dt as a ratio from original dt", "TSPseudoIncrementDtFromInitialDt", flg, &flg, NULL));
322: pseudo->increment_dt_from_initial_dt = flg;
323: PetscCall(PetscOptionsReal("-ts_pseudo_increment", "Ratio to increase dt", "TSPseudoSetTimeStepIncrement", pseudo->dt_increment, &pseudo->dt_increment, NULL));
324: PetscCall(PetscOptionsReal("-ts_pseudo_max_dt", "Maximum value for dt", "TSPseudoSetMaxTimeStep", pseudo->dt_max, &pseudo->dt_max, NULL));
325: PetscCall(PetscOptionsReal("-ts_pseudo_fatol", "Tolerance for norm of function", "", pseudo->fatol, &pseudo->fatol, NULL));
326: PetscCall(PetscOptionsReal("-ts_pseudo_frtol", "Relative tolerance for norm of function", "", pseudo->frtol, &pseudo->frtol, NULL));
327: PetscOptionsHeadEnd();
328: PetscFunctionReturn(PETSC_SUCCESS);
329: }
331: static PetscErrorCode TSView_Pseudo(TS ts, PetscViewer viewer)
332: {
333: PetscBool isascii;
335: PetscFunctionBegin;
336: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
337: if (isascii) {
338: TS_Pseudo *pseudo = (TS_Pseudo *)ts->data;
339: PetscCall(PetscViewerASCIIPrintf(viewer, " frtol - relative tolerance in function value %g\n", (double)pseudo->frtol));
340: PetscCall(PetscViewerASCIIPrintf(viewer, " fatol - absolute tolerance in function value %g\n", (double)pseudo->fatol));
341: PetscCall(PetscViewerASCIIPrintf(viewer, " dt_initial - initial timestep %g\n", (double)pseudo->dt_initial));
342: PetscCall(PetscViewerASCIIPrintf(viewer, " dt_increment - increase in timestep on successful step %g\n", (double)pseudo->dt_increment));
343: PetscCall(PetscViewerASCIIPrintf(viewer, " dt_max - maximum time %g\n", (double)pseudo->dt_max));
344: }
345: PetscFunctionReturn(PETSC_SUCCESS);
346: }
348: /* ----------------------------------------------------------------------------- */
349: /*@C
350: TSPseudoSetVerifyTimeStep - Sets a user-defined routine to verify the quality of the
351: last timestep.
353: Logically Collective
355: Input Parameters:
356: + ts - timestep context
357: . dt - user-defined function to verify timestep
358: - ctx - [optional] user-defined context for private data
359: for the timestep verification routine (may be NULL)
361: Calling sequence of func:
362: $ func (TS ts,Vec update,void *ctx,PetscReal *newdt,PetscBool *flag);
364: + update - latest solution vector
365: . ctx - [optional] timestep context
366: . newdt - the timestep to use for the next step
367: - flag - flag indicating whether the last time step was acceptable
369: Level: advanced
371: Note:
372: The routine set here will be called by `TSPseudoVerifyTimeStep()`
373: during the timestepping process.
375: .seealso: [](chapter_ts), `TSPSEUDO`, `TSPseudoVerifyTimeStepDefault()`, `TSPseudoVerifyTimeStep()`
376: @*/
377: PetscErrorCode TSPseudoSetVerifyTimeStep(TS ts, PetscErrorCode (*dt)(TS, Vec, void *, PetscReal *, PetscBool *), void *ctx)
378: {
379: PetscFunctionBegin;
381: PetscTryMethod(ts, "TSPseudoSetVerifyTimeStep_C", (TS, PetscErrorCode(*)(TS, Vec, void *, PetscReal *, PetscBool *), void *), (ts, dt, ctx));
382: PetscFunctionReturn(PETSC_SUCCESS);
383: }
385: /*@
386: TSPseudoSetTimeStepIncrement - Sets the scaling increment applied to
387: dt when using the TSPseudoTimeStepDefault() routine.
389: Logically Collective
391: Input Parameters:
392: + ts - the timestep context
393: - inc - the scaling factor >= 1.0
395: Options Database Key:
396: . -ts_pseudo_increment <increment> - set pseudo increment
398: Level: advanced
400: .seealso: [](chapter_ts), `TSPSEUDO`, `TSPseudoSetTimeStep()`, `TSPseudoTimeStepDefault()`
401: @*/
402: PetscErrorCode TSPseudoSetTimeStepIncrement(TS ts, PetscReal inc)
403: {
404: PetscFunctionBegin;
407: PetscTryMethod(ts, "TSPseudoSetTimeStepIncrement_C", (TS, PetscReal), (ts, inc));
408: PetscFunctionReturn(PETSC_SUCCESS);
409: }
411: /*@
412: TSPseudoSetMaxTimeStep - Sets the maximum time step
413: when using the TSPseudoTimeStepDefault() routine.
415: Logically Collective
417: Input Parameters:
418: + ts - the timestep context
419: - maxdt - the maximum time step, use a non-positive value to deactivate
421: Options Database Key:
422: . -ts_pseudo_max_dt <increment> - set pseudo max dt
424: Level: advanced
426: .seealso: [](chapter_ts), `TSPSEUDO`, `TSPseudoSetTimeStep()`, `TSPseudoTimeStepDefault()`
427: @*/
428: PetscErrorCode TSPseudoSetMaxTimeStep(TS ts, PetscReal maxdt)
429: {
430: PetscFunctionBegin;
433: PetscTryMethod(ts, "TSPseudoSetMaxTimeStep_C", (TS, PetscReal), (ts, maxdt));
434: PetscFunctionReturn(PETSC_SUCCESS);
435: }
437: /*@
438: TSPseudoIncrementDtFromInitialDt - Indicates that a new timestep
439: is computed via the formula
440: $ dt = initial_dt*initial_fnorm/current_fnorm
441: rather than the default update,
442: $ dt = current_dt*previous_fnorm/current_fnorm.
444: Logically Collective
446: Input Parameter:
447: . ts - the timestep context
449: Options Database Key:
450: . -ts_pseudo_increment_dt_from_initial_dt <true,false> - use the initial dt to determine increment
452: Level: advanced
454: .seealso: [](chapter_ts), `TSPSEUDO`, `TSPseudoSetTimeStep()`, `TSPseudoTimeStepDefault()`
455: @*/
456: PetscErrorCode TSPseudoIncrementDtFromInitialDt(TS ts)
457: {
458: PetscFunctionBegin;
460: PetscTryMethod(ts, "TSPseudoIncrementDtFromInitialDt_C", (TS), (ts));
461: PetscFunctionReturn(PETSC_SUCCESS);
462: }
464: /*@C
465: TSPseudoSetTimeStep - Sets the user-defined routine to be
466: called at each pseudo-timestep to update the timestep.
468: Logically Collective
470: Input Parameters:
471: + ts - timestep context
472: . dt - function to compute timestep
473: - ctx - [optional] user-defined context for private data
474: required by the function (may be NULL)
476: Calling sequence of func:
477: $ func (TS ts,PetscReal *newdt,void *ctx);
479: + newdt - the newly computed timestep
480: - ctx - [optional] timestep context
482: Level: intermediate
484: Notes:
485: The routine set here will be called by `TSPseudoComputeTimeStep()`
486: during the timestepping process.
488: If not set then `TSPseudoTimeStepDefault()` is automatically used
490: .seealso: [](chapter_ts), `TSPSEUDO`, `TSPseudoTimeStepDefault()`, `TSPseudoComputeTimeStep()`
491: @*/
492: PetscErrorCode TSPseudoSetTimeStep(TS ts, PetscErrorCode (*dt)(TS, PetscReal *, void *), void *ctx)
493: {
494: PetscFunctionBegin;
496: PetscTryMethod(ts, "TSPseudoSetTimeStep_C", (TS, PetscErrorCode(*)(TS, PetscReal *, void *), void *), (ts, dt, ctx));
497: PetscFunctionReturn(PETSC_SUCCESS);
498: }
500: /* ----------------------------------------------------------------------------- */
502: typedef PetscErrorCode (*FCN1)(TS, Vec, void *, PetscReal *, PetscBool *); /* force argument to next function to not be extern C*/
503: static PetscErrorCode TSPseudoSetVerifyTimeStep_Pseudo(TS ts, FCN1 dt, void *ctx)
504: {
505: TS_Pseudo *pseudo = (TS_Pseudo *)ts->data;
507: PetscFunctionBegin;
508: pseudo->verify = dt;
509: pseudo->verifyctx = ctx;
510: PetscFunctionReturn(PETSC_SUCCESS);
511: }
513: static PetscErrorCode TSPseudoSetTimeStepIncrement_Pseudo(TS ts, PetscReal inc)
514: {
515: TS_Pseudo *pseudo = (TS_Pseudo *)ts->data;
517: PetscFunctionBegin;
518: pseudo->dt_increment = inc;
519: PetscFunctionReturn(PETSC_SUCCESS);
520: }
522: static PetscErrorCode TSPseudoSetMaxTimeStep_Pseudo(TS ts, PetscReal maxdt)
523: {
524: TS_Pseudo *pseudo = (TS_Pseudo *)ts->data;
526: PetscFunctionBegin;
527: pseudo->dt_max = maxdt;
528: PetscFunctionReturn(PETSC_SUCCESS);
529: }
531: static PetscErrorCode TSPseudoIncrementDtFromInitialDt_Pseudo(TS ts)
532: {
533: TS_Pseudo *pseudo = (TS_Pseudo *)ts->data;
535: PetscFunctionBegin;
536: pseudo->increment_dt_from_initial_dt = PETSC_TRUE;
537: PetscFunctionReturn(PETSC_SUCCESS);
538: }
540: typedef PetscErrorCode (*FCN2)(TS, PetscReal *, void *); /* force argument to next function to not be extern C*/
541: static PetscErrorCode TSPseudoSetTimeStep_Pseudo(TS ts, FCN2 dt, void *ctx)
542: {
543: TS_Pseudo *pseudo = (TS_Pseudo *)ts->data;
545: PetscFunctionBegin;
546: pseudo->dt = dt;
547: pseudo->dtctx = ctx;
548: PetscFunctionReturn(PETSC_SUCCESS);
549: }
551: /* ----------------------------------------------------------------------------- */
552: /*MC
553: TSPSEUDO - Solve steady state ODE and DAE problems with pseudo time stepping
555: This method solves equations of the form
557: $ F(X,Xdot) = 0
559: for steady state using the iteration
561: $ [G'] S = -F(X,0)
562: $ X += S
564: where
566: $ G(Y) = F(Y,(Y-X)/dt)
568: This is linearly-implicit Euler with the residual always evaluated "at steady
569: state". See note below.
571: Options Database Keys:
572: + -ts_pseudo_increment <real> - ratio of increase dt
573: . -ts_pseudo_increment_dt_from_initial_dt <truth> - Increase dt as a ratio from original dt
574: . -ts_pseudo_fatol <atol> - stop iterating when the function norm is less than atol
575: - -ts_pseudo_frtol <rtol> - stop iterating when the function norm divided by the initial function norm is less than rtol
577: Level: beginner
579: Notes:
580: The residual computed by this method includes the transient term (Xdot is computed instead of
581: always being zero), but since the prediction from the last step is always the solution from the
582: last step, on the first Newton iteration we have
584: $ Xdot = (Xpredicted - Xold)/dt = (Xold-Xold)/dt = 0
586: Therefore, the linear system solved by the first Newton iteration is equivalent to the one
587: described above and in the papers. If the user chooses to perform multiple Newton iterations, the
588: algorithm is no longer the one described in the referenced papers.
590: References:
591: + * - Todd S. Coffey and C. T. Kelley and David E. Keyes, Pseudotransient Continuation and Differential Algebraic Equations, 2003.
592: - * - C. T. Kelley and David E. Keyes, Convergence analysis of Pseudotransient Continuation, 1998.
594: .seealso: [](chapter_ts), `TSCreate()`, `TS`, `TSSetType()`
595: M*/
596: PETSC_EXTERN PetscErrorCode TSCreate_Pseudo(TS ts)
597: {
598: TS_Pseudo *pseudo;
599: SNES snes;
600: SNESType stype;
602: PetscFunctionBegin;
603: ts->ops->reset = TSReset_Pseudo;
604: ts->ops->destroy = TSDestroy_Pseudo;
605: ts->ops->view = TSView_Pseudo;
606: ts->ops->setup = TSSetUp_Pseudo;
607: ts->ops->step = TSStep_Pseudo;
608: ts->ops->setfromoptions = TSSetFromOptions_Pseudo;
609: ts->ops->snesfunction = SNESTSFormFunction_Pseudo;
610: ts->ops->snesjacobian = SNESTSFormJacobian_Pseudo;
611: ts->default_adapt_type = TSADAPTNONE;
612: ts->usessnes = PETSC_TRUE;
614: PetscCall(TSGetSNES(ts, &snes));
615: PetscCall(SNESGetType(snes, &stype));
616: if (!stype) PetscCall(SNESSetType(snes, SNESKSPONLY));
618: PetscCall(PetscNew(&pseudo));
619: ts->data = (void *)pseudo;
621: pseudo->dt = TSPseudoTimeStepDefault;
622: pseudo->dtctx = NULL;
623: pseudo->dt_increment = 1.1;
624: pseudo->increment_dt_from_initial_dt = PETSC_FALSE;
625: pseudo->fnorm = -1;
626: pseudo->fnorm_initial = -1;
627: pseudo->fnorm_previous = -1;
628: #if defined(PETSC_USE_REAL_SINGLE)
629: pseudo->fatol = 1.e-25;
630: pseudo->frtol = 1.e-5;
631: #else
632: pseudo->fatol = 1.e-50;
633: pseudo->frtol = 1.e-12;
634: #endif
635: PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSPseudoSetVerifyTimeStep_C", TSPseudoSetVerifyTimeStep_Pseudo));
636: PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSPseudoSetTimeStepIncrement_C", TSPseudoSetTimeStepIncrement_Pseudo));
637: PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSPseudoSetMaxTimeStep_C", TSPseudoSetMaxTimeStep_Pseudo));
638: PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSPseudoIncrementDtFromInitialDt_C", TSPseudoIncrementDtFromInitialDt_Pseudo));
639: PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSPseudoSetTimeStep_C", TSPseudoSetTimeStep_Pseudo));
640: PetscFunctionReturn(PETSC_SUCCESS);
641: }
643: /*@C
644: TSPseudoTimeStepDefault - Default code to compute pseudo-timestepping. Use with `TSPseudoSetTimeStep()`.
646: Collective
648: Input Parameters:
649: + ts - the timestep context
650: - dtctx - unused timestep context
652: Output Parameter:
653: . newdt - the timestep to use for the next step
655: Level: advanced
657: .seealso: [](chapter_ts), `TSPseudoSetTimeStep()`, `TSPseudoComputeTimeStep()`, `TSPSEUDO`
658: @*/
659: PetscErrorCode TSPseudoTimeStepDefault(TS ts, PetscReal *newdt, void *dtctx)
660: {
661: TS_Pseudo *pseudo = (TS_Pseudo *)ts->data;
662: PetscReal inc = pseudo->dt_increment;
664: PetscFunctionBegin;
665: PetscCall(VecZeroEntries(pseudo->xdot));
666: PetscCall(TSComputeIFunction(ts, ts->ptime, ts->vec_sol, pseudo->xdot, pseudo->func, PETSC_FALSE));
667: PetscCall(VecNorm(pseudo->func, NORM_2, &pseudo->fnorm));
668: if (pseudo->fnorm_initial < 0) {
669: /* first time through so compute initial function norm */
670: pseudo->fnorm_initial = pseudo->fnorm;
671: pseudo->fnorm_previous = pseudo->fnorm;
672: }
673: if (pseudo->fnorm == 0.0) *newdt = 1.e12 * inc * ts->time_step;
674: else if (pseudo->increment_dt_from_initial_dt) *newdt = inc * pseudo->dt_initial * pseudo->fnorm_initial / pseudo->fnorm;
675: else *newdt = inc * ts->time_step * pseudo->fnorm_previous / pseudo->fnorm;
676: if (pseudo->dt_max > 0) *newdt = PetscMin(*newdt, pseudo->dt_max);
677: pseudo->fnorm_previous = pseudo->fnorm;
678: PetscFunctionReturn(PETSC_SUCCESS);
679: }