xref: /petsc/src/ts/impls/pseudo/posindep.c (revision 4e8208cbcbc709572b8abe32f33c78b69c819375)
12d3f70b5SBarry Smith /*
2fb4a63b6SLois Curfman McInnes        Code for Timestepping with implicit backwards Euler.
32d3f70b5SBarry Smith */
4af0996ceSBarry Smith #include <petsc/private/tsimpl.h> /*I   "petscts.h"   I*/
52d3f70b5SBarry Smith 
6c558785fSJames Wright #define TSADAPTTSPSEUDO "tspseudo"
7c558785fSJames Wright 
82d3f70b5SBarry Smith typedef struct {
92d3f70b5SBarry Smith   Vec func; /* work vector where F(t[i],u[i]) is stored */
106f2d6a7bSJed Brown   Vec xdot; /* work vector for time derivative of state */
112d3f70b5SBarry Smith 
122d3f70b5SBarry Smith   /* information used for Pseudo-timestepping */
132d3f70b5SBarry Smith 
146849ba73SBarry Smith   PetscErrorCode (*dt)(TS, PetscReal *, void *); /* compute next timestep, and related context */
152d3f70b5SBarry Smith   void *dtctx;
16ace3abfcSBarry Smith   PetscErrorCode (*verify)(TS, Vec, void *, PetscReal *, PetscBool *); /* verify previous timestep and related context */
177bf11e45SBarry Smith   void *verifyctx;
182d3f70b5SBarry Smith 
19cdbf8f93SLisandro Dalcin   PetscReal fnorm_initial, fnorm; /* original and current norm of F(u) */
2087828ca2SBarry Smith   PetscReal fnorm_previous;
2128aa8177SBarry Smith 
22cdbf8f93SLisandro Dalcin   PetscReal dt_initial;   /* initial time-step */
2387828ca2SBarry Smith   PetscReal dt_increment; /* scaling that dt is incremented each time-step */
2486534af1SJed Brown   PetscReal dt_max;       /* maximum time step */
25ace3abfcSBarry Smith   PetscBool increment_dt_from_initial_dt;
263118ae5eSBarry Smith   PetscReal fatol, frtol;
27eb636060SBarry Smith 
28eb636060SBarry Smith   PetscObjectState Xstate; /* state of input vector to TSComputeIFunction() with 0 Xdot */
29940ebdd4SJames Wright 
30940ebdd4SJames Wright   TSStepStatus status;
317bf11e45SBarry Smith } TS_Pseudo;
322d3f70b5SBarry Smith 
330fe2f5c2SJames Wright /*@C
340fe2f5c2SJames Wright   TSPseudoComputeFunction - Compute nonlinear residual for pseudo-timestepping
350fe2f5c2SJames Wright 
360fe2f5c2SJames Wright   This computes the residual for $\dot U = 0$, i.e. $F(U, 0)$ for the IFunction.
370fe2f5c2SJames Wright 
380fe2f5c2SJames Wright   Collective
390fe2f5c2SJames Wright 
400fe2f5c2SJames Wright   Input Parameters:
410fe2f5c2SJames Wright + ts       - the timestep context
420fe2f5c2SJames Wright - solution - the solution vector
430fe2f5c2SJames Wright 
440fe2f5c2SJames Wright   Output Parameter:
450fe2f5c2SJames Wright + residual - the nonlinear residual
460fe2f5c2SJames Wright - fnorm    - the norm of the nonlinear residual
470fe2f5c2SJames Wright 
480fe2f5c2SJames Wright   Level: advanced
490fe2f5c2SJames Wright 
500fe2f5c2SJames Wright   Note:
510fe2f5c2SJames Wright   `TSPSEUDO` records the nonlinear residual and the `solution` vector used to generate it. If given the same `solution` vector (as determined by the vectors `PetscObjectState`), this function will return those recorded values.
520fe2f5c2SJames Wright 
530fe2f5c2SJames Wright   This would be used in a custom adaptive timestepping implementation that needs access to the residual, but reuses the calculation done by `TSPSEUDO` by default.
540fe2f5c2SJames Wright 
55f7782ccaSJames Wright   To correctly get the residual reuse behavior, `solution` must be the same `Vec` that returned by `TSGetSolution()`.
56f7782ccaSJames Wright 
570fe2f5c2SJames Wright .seealso: [](ch_ts), `TSPSEUDO`
580fe2f5c2SJames Wright @*/
TSPseudoComputeFunction(TS ts,Vec solution,Vec * residual,PetscReal * fnorm)590fe2f5c2SJames Wright PetscErrorCode TSPseudoComputeFunction(TS ts, Vec solution, Vec *residual, PetscReal *fnorm)
600fe2f5c2SJames Wright {
610fe2f5c2SJames Wright   TS_Pseudo       *pseudo = (TS_Pseudo *)ts->data;
620fe2f5c2SJames Wright   PetscObjectState Xstate;
630fe2f5c2SJames Wright 
640fe2f5c2SJames Wright   PetscFunctionBegin;
650fe2f5c2SJames Wright   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
660fe2f5c2SJames Wright   PetscValidHeaderSpecific(solution, VEC_CLASSID, 2);
670fe2f5c2SJames Wright   if (residual) PetscValidHeaderSpecific(*residual, VEC_CLASSID, 3);
680fe2f5c2SJames Wright   if (fnorm) PetscAssertPointer(fnorm, 4);
690fe2f5c2SJames Wright 
700fe2f5c2SJames Wright   PetscCall(PetscObjectStateGet((PetscObject)solution, &Xstate));
710fe2f5c2SJames Wright   if (Xstate != pseudo->Xstate || pseudo->fnorm < 0) {
720fe2f5c2SJames Wright     PetscCall(VecZeroEntries(pseudo->xdot));
730fe2f5c2SJames Wright     PetscCall(TSComputeIFunction(ts, ts->ptime, solution, pseudo->xdot, pseudo->func, PETSC_FALSE));
740fe2f5c2SJames Wright     pseudo->Xstate = Xstate;
750fe2f5c2SJames Wright     PetscCall(VecNorm(pseudo->func, NORM_2, &pseudo->fnorm));
760fe2f5c2SJames Wright   }
770fe2f5c2SJames Wright   if (residual) *residual = pseudo->func;
780fe2f5c2SJames Wright   if (fnorm) *fnorm = pseudo->fnorm;
790fe2f5c2SJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
800fe2f5c2SJames Wright }
810fe2f5c2SJames Wright 
TSStep_Pseudo(TS ts)82d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSStep_Pseudo(TS ts)
83d71ae5a4SJacob Faibussowitsch {
84277b19d0SLisandro Dalcin   TS_Pseudo *pseudo = (TS_Pseudo *)ts->data;
85940ebdd4SJames Wright   PetscInt   nits, lits, rejections = 0;
86940ebdd4SJames Wright   PetscBool  accept;
87c2cf51afSJames Wright   PetscReal  next_time_step = ts->time_step, fnorm;
88c558785fSJames Wright   TSAdapt    adapt;
892d3f70b5SBarry Smith 
903a40ed3dSBarry Smith   PetscFunctionBegin;
91f7782ccaSJames Wright   if (ts->steps == 0) pseudo->dt_initial = ts->time_step;
92940ebdd4SJames Wright 
93940ebdd4SJames Wright   pseudo->status = TS_STEP_INCOMPLETE;
94940ebdd4SJames Wright   while (!ts->reason && pseudo->status != TS_STEP_COMPLETE) {
959566063dSJacob Faibussowitsch     PetscCall(TSPreStage(ts, ts->ptime + ts->time_step));
96f7782ccaSJames Wright     PetscCall(SNESSolve(ts->snes, NULL, ts->vec_sol));
979566063dSJacob Faibussowitsch     PetscCall(SNESGetIterationNumber(ts->snes, &nits));
989566063dSJacob Faibussowitsch     PetscCall(SNESGetLinearSolveIterations(ts->snes, &lits));
999371c9d4SSatish Balay     ts->snes_its += nits;
1009371c9d4SSatish Balay     ts->ksp_its += lits;
101c558785fSJames Wright     pseudo->fnorm = -1; /* The current norm is no longer valid */
102f7782ccaSJames Wright     PetscCall(TSPostStage(ts, ts->ptime + ts->time_step, 0, &ts->vec_sol));
103c558785fSJames Wright     PetscCall(TSGetAdapt(ts, &adapt));
104f7782ccaSJames Wright     PetscCall(TSAdaptCheckStage(adapt, ts, ts->ptime + ts->time_step, ts->vec_sol, &accept));
105940ebdd4SJames Wright     if (!accept) goto reject_step;
106be5899b3SLisandro Dalcin 
107940ebdd4SJames Wright     pseudo->status = TS_STEP_PENDING;
108940ebdd4SJames Wright     PetscCall(TSAdaptChoose(adapt, ts, ts->time_step, NULL, &next_time_step, &accept));
109940ebdd4SJames Wright     pseudo->status = accept ? TS_STEP_COMPLETE : TS_STEP_INCOMPLETE;
110940ebdd4SJames Wright     if (!accept) {
111940ebdd4SJames Wright       ts->time_step = next_time_step;
112940ebdd4SJames Wright       goto reject_step;
113940ebdd4SJames Wright     }
114be5899b3SLisandro Dalcin     ts->ptime += ts->time_step;
115be5899b3SLisandro Dalcin     ts->time_step = next_time_step;
116940ebdd4SJames Wright     break;
117be5899b3SLisandro Dalcin 
118940ebdd4SJames Wright   reject_step:
119940ebdd4SJames Wright     ts->reject++;
120940ebdd4SJames Wright     accept = PETSC_FALSE;
121f7782ccaSJames Wright     PetscCall(VecCopy(ts->vec_sol0, ts->vec_sol));
122940ebdd4SJames Wright     if (!ts->reason && ++rejections > ts->max_reject && ts->max_reject >= 0) {
123940ebdd4SJames Wright       ts->reason = TS_DIVERGED_STEP_REJECTED;
124940ebdd4SJames Wright       PetscCall(PetscInfo(ts, "Step=%" PetscInt_FMT ", step rejections %" PetscInt_FMT " greater than current TS allowed, stopping solve\n", ts->steps, rejections));
125940ebdd4SJames Wright       PetscFunctionReturn(PETSC_SUCCESS);
126940ebdd4SJames Wright     }
127940ebdd4SJames Wright   }
128940ebdd4SJames Wright 
129940ebdd4SJames Wright   // Check solution convergence
130c2cf51afSJames Wright   PetscCall(TSPseudoComputeFunction(ts, ts->vec_sol, NULL, &fnorm));
131eb636060SBarry Smith 
132c2cf51afSJames Wright   if (fnorm < pseudo->fatol) {
1333118ae5eSBarry Smith     ts->reason = TS_CONVERGED_PSEUDO_FATOL;
13463a3b9bcSJacob Faibussowitsch     PetscCall(PetscInfo(ts, "Step=%" PetscInt_FMT ", converged since fnorm %g < fatol %g\n", ts->steps, (double)pseudo->fnorm, (double)pseudo->frtol));
1353ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
1363118ae5eSBarry Smith   }
137c2cf51afSJames Wright   if (fnorm / pseudo->fnorm_initial < pseudo->frtol) {
1383118ae5eSBarry Smith     ts->reason = TS_CONVERGED_PSEUDO_FRTOL;
13963a3b9bcSJacob Faibussowitsch     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));
1403ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
1413118ae5eSBarry Smith   }
1423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1432d3f70b5SBarry Smith }
1442d3f70b5SBarry Smith 
TSReset_Pseudo(TS ts)145d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSReset_Pseudo(TS ts)
146d71ae5a4SJacob Faibussowitsch {
1477bf11e45SBarry Smith   TS_Pseudo *pseudo = (TS_Pseudo *)ts->data;
1482d3f70b5SBarry Smith 
1493a40ed3dSBarry Smith   PetscFunctionBegin;
1509566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pseudo->func));
1519566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&pseudo->xdot));
1523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1532d3f70b5SBarry Smith }
1542d3f70b5SBarry Smith 
TSDestroy_Pseudo(TS ts)155d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSDestroy_Pseudo(TS ts)
156d71ae5a4SJacob Faibussowitsch {
157277b19d0SLisandro Dalcin   PetscFunctionBegin;
1589566063dSJacob Faibussowitsch   PetscCall(TSReset_Pseudo(ts));
1599566063dSJacob Faibussowitsch   PetscCall(PetscFree(ts->data));
1609566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSPseudoSetVerifyTimeStep_C", NULL));
1619566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSPseudoSetTimeStepIncrement_C", NULL));
1629566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSPseudoSetMaxTimeStep_C", NULL));
1639566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSPseudoIncrementDtFromInitialDt_C", NULL));
1649566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSPseudoSetTimeStep_C", NULL));
1653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
166277b19d0SLisandro Dalcin }
1672d3f70b5SBarry Smith 
TSPseudoGetXdot(TS ts,Vec X,Vec * Xdot)168d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSPseudoGetXdot(TS ts, Vec X, Vec *Xdot)
169d71ae5a4SJacob Faibussowitsch {
1706f2d6a7bSJed Brown   TS_Pseudo *pseudo = (TS_Pseudo *)ts->data;
1712d3f70b5SBarry Smith 
1723a40ed3dSBarry Smith   PetscFunctionBegin;
1736f2d6a7bSJed Brown   *Xdot = pseudo->xdot;
1743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
1752d3f70b5SBarry Smith }
1762d3f70b5SBarry Smith 
1776f2d6a7bSJed Brown /*
1786f2d6a7bSJed Brown     The transient residual is
1796f2d6a7bSJed Brown 
1806f2d6a7bSJed Brown         F(U^{n+1},(U^{n+1}-U^n)/dt) = 0
1816f2d6a7bSJed Brown 
1826f2d6a7bSJed Brown     or for ODE,
1836f2d6a7bSJed Brown 
1846f2d6a7bSJed Brown         (U^{n+1} - U^{n})/dt - F(U^{n+1}) = 0
1856f2d6a7bSJed Brown 
1866f2d6a7bSJed Brown     This is the function that must be evaluated for transient simulation and for
1876f2d6a7bSJed Brown     finite difference Jacobians.  On the first Newton step, this algorithm uses
1886f2d6a7bSJed Brown     a guess of U^{n+1} = U^n in which case the transient term vanishes and the
1896f2d6a7bSJed Brown     residual is actually the steady state residual.  Pseudotransient
1906f2d6a7bSJed Brown     continuation as described in the literature is a linearly implicit
191eb636060SBarry Smith     algorithm, it only takes this one full Newton step with the steady state
1926f2d6a7bSJed Brown     residual, and then advances to the next time step.
193eb636060SBarry Smith 
194eb636060SBarry Smith     This routine avoids a repeated identical call to TSComputeRHSFunction() when that result
195eb636060SBarry Smith     is already contained in pseudo->func due to the call to TSComputeIFunction() in TSStep_Pseudo()
196eb636060SBarry Smith 
1976f2d6a7bSJed Brown */
SNESTSFormFunction_Pseudo(SNES snes,Vec X,Vec Y,TS ts)198d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESTSFormFunction_Pseudo(SNES snes, Vec X, Vec Y, TS ts)
199d71ae5a4SJacob Faibussowitsch {
200eb636060SBarry Smith   TSIFunctionFn    *ifunction;
201eb636060SBarry Smith   TSRHSFunctionFn  *rhsfunction;
202eb636060SBarry Smith   void             *ctx;
203eb636060SBarry Smith   DM                dm;
204eb636060SBarry Smith   TS_Pseudo        *pseudo = (TS_Pseudo *)ts->data;
20581775c15SStefano Zampini   const PetscScalar mdt    = 1.0 / ts->time_step;
206eb636060SBarry Smith   PetscObjectState  Xstate;
207e344a936SJames Wright   PetscInt          snes_it;
2082d3f70b5SBarry Smith 
2093a40ed3dSBarry Smith   PetscFunctionBegin;
210eb636060SBarry Smith   PetscValidHeaderSpecific(snes, SNES_CLASSID, 1);
211eb636060SBarry Smith   PetscValidHeaderSpecific(X, VEC_CLASSID, 2);
212eb636060SBarry Smith   PetscValidHeaderSpecific(Y, VEC_CLASSID, 3);
213eb636060SBarry Smith   PetscValidHeaderSpecific(ts, TS_CLASSID, 4);
214eb636060SBarry Smith 
215eb636060SBarry Smith   PetscCall(TSGetDM(ts, &dm));
216eb636060SBarry Smith   PetscCall(DMTSGetIFunction(dm, &ifunction, &ctx));
217eb636060SBarry Smith   PetscCall(DMTSGetRHSFunction(dm, &rhsfunction, NULL));
218eb636060SBarry Smith   PetscCheck(rhsfunction || ifunction, PetscObjectComm((PetscObject)ts), PETSC_ERR_USER, "Must call TSSetRHSFunction() and / or TSSetIFunction()");
219eb636060SBarry Smith 
220eb636060SBarry Smith   PetscCall(PetscObjectStateGet((PetscObject)X, &Xstate));
221e344a936SJames Wright   PetscCall(SNESGetIterationNumber(snes, &snes_it));
222e344a936SJames Wright   if (Xstate == pseudo->Xstate && snes_it == 1) {
223e344a936SJames Wright     /* reuse the TSComputeIFunction() result performed inside TSStep_Pseudo() */
224e344a936SJames Wright     if (ifunction) PetscCall(VecCopy(pseudo->func, Y));
225e344a936SJames Wright     /* note that pseudo->func contains the negation of TSComputeRHSFunction() */
226e344a936SJames Wright     else PetscCall(VecWAXPY(Y, 1, pseudo->func, pseudo->xdot));
227e344a936SJames Wright   } else {
228f7782ccaSJames Wright     PetscCall(VecAXPBYPCZ(pseudo->xdot, -mdt, mdt, 0, ts->vec_sol0, X));
22981775c15SStefano Zampini     PetscCall(TSComputeIFunction(ts, ts->ptime + ts->time_step, X, pseudo->xdot, Y, PETSC_FALSE));
230eb636060SBarry Smith   }
2313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2326f2d6a7bSJed Brown }
2332d3f70b5SBarry Smith 
2346f2d6a7bSJed Brown /*
2356f2d6a7bSJed Brown    This constructs the Jacobian needed for SNES.  For DAE, this is
2366f2d6a7bSJed Brown 
2376f2d6a7bSJed Brown        dF(X,Xdot)/dX + shift*dF(X,Xdot)/dXdot
2386f2d6a7bSJed Brown 
2396f2d6a7bSJed Brown     and for ODE:
2406f2d6a7bSJed Brown 
2416f2d6a7bSJed Brown        J = I/dt - J_{Frhs}   where J_{Frhs} is the given Jacobian of Frhs.
2426f2d6a7bSJed Brown */
SNESTSFormJacobian_Pseudo(SNES snes,Vec X,Mat AA,Mat BB,TS ts)243d71ae5a4SJacob Faibussowitsch static PetscErrorCode SNESTSFormJacobian_Pseudo(SNES snes, Vec X, Mat AA, Mat BB, TS ts)
244d71ae5a4SJacob Faibussowitsch {
2456f2d6a7bSJed Brown   Vec Xdot;
2466f2d6a7bSJed Brown 
2476f2d6a7bSJed Brown   PetscFunctionBegin;
24881775c15SStefano Zampini   /* Xdot has already been computed in SNESTSFormFunction_Pseudo (SNES guarantees this) */
2499566063dSJacob Faibussowitsch   PetscCall(TSPseudoGetXdot(ts, X, &Xdot));
2509566063dSJacob Faibussowitsch   PetscCall(TSComputeIJacobian(ts, ts->ptime + ts->time_step, X, Xdot, 1. / ts->time_step, AA, BB, PETSC_FALSE));
2513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2522d3f70b5SBarry Smith }
2532d3f70b5SBarry Smith 
TSSetUp_Pseudo(TS ts)254d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSSetUp_Pseudo(TS ts)
255d71ae5a4SJacob Faibussowitsch {
2567bf11e45SBarry Smith   TS_Pseudo *pseudo = (TS_Pseudo *)ts->data;
2572d3f70b5SBarry Smith 
2583a40ed3dSBarry Smith   PetscFunctionBegin;
2599566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(ts->vec_sol, &pseudo->func));
2609566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(ts->vec_sol, &pseudo->xdot));
2613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2622d3f70b5SBarry Smith }
26381775c15SStefano Zampini 
TSPseudoMonitorDefault(TS ts,PetscInt step,PetscReal ptime,Vec v,void * dummy)264d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSPseudoMonitorDefault(TS ts, PetscInt step, PetscReal ptime, Vec v, void *dummy)
265d71ae5a4SJacob Faibussowitsch {
2667bf11e45SBarry Smith   TS_Pseudo  *pseudo = (TS_Pseudo *)ts->data;
267ce94432eSBarry Smith   PetscViewer viewer = (PetscViewer)dummy;
2682d3f70b5SBarry Smith 
2693a40ed3dSBarry Smith   PetscFunctionBegin;
2700fe2f5c2SJames Wright   PetscCall(TSPseudoComputeFunction(ts, ts->vec_sol, NULL, NULL));
2719566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIAddTab(viewer, ((PetscObject)ts)->tablevel));
27263a3b9bcSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPrintf(viewer, "TS %" PetscInt_FMT " dt %g time %g fnorm %g\n", step, (double)ts->time_step, (double)ptime, (double)pseudo->fnorm));
2739566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIISubtractTab(viewer, ((PetscObject)ts)->tablevel));
2743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2752d3f70b5SBarry Smith }
2762d3f70b5SBarry Smith 
TSSetFromOptions_Pseudo(TS ts,PetscOptionItems PetscOptionsObject)277ce78bad3SBarry Smith static PetscErrorCode TSSetFromOptions_Pseudo(TS ts, PetscOptionItems PetscOptionsObject)
278d71ae5a4SJacob Faibussowitsch {
2794bbc92c1SBarry Smith   TS_Pseudo  *pseudo = (TS_Pseudo *)ts->data;
280ace3abfcSBarry Smith   PetscBool   flg    = PETSC_FALSE;
281649052a6SBarry Smith   PetscViewer viewer;
2822d3f70b5SBarry Smith 
2833a40ed3dSBarry Smith   PetscFunctionBegin;
284d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "Pseudo-timestepping options");
2859566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-ts_monitor_pseudo", "Monitor convergence", "", flg, &flg, NULL));
2862d3f70b5SBarry Smith   if (flg) {
2879566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIOpen(PetscObjectComm((PetscObject)ts), "stdout", &viewer));
28849abdd8aSBarry Smith     PetscCall(TSMonitorSet(ts, TSPseudoMonitorDefault, viewer, (PetscCtxDestroyFn *)PetscViewerDestroy));
28928aa8177SBarry Smith   }
290be5899b3SLisandro Dalcin   flg = pseudo->increment_dt_from_initial_dt;
2919566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-ts_pseudo_increment_dt_from_initial_dt", "Increase dt as a ratio from original dt", "TSPseudoIncrementDtFromInitialDt", flg, &flg, NULL));
292be5899b3SLisandro Dalcin   pseudo->increment_dt_from_initial_dt = flg;
2939566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-ts_pseudo_increment", "Ratio to increase dt", "TSPseudoSetTimeStepIncrement", pseudo->dt_increment, &pseudo->dt_increment, NULL));
2949566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-ts_pseudo_max_dt", "Maximum value for dt", "TSPseudoSetMaxTimeStep", pseudo->dt_max, &pseudo->dt_max, NULL));
2959566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-ts_pseudo_fatol", "Tolerance for norm of function", "", pseudo->fatol, &pseudo->fatol, NULL));
2969566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-ts_pseudo_frtol", "Relative tolerance for norm of function", "", pseudo->frtol, &pseudo->frtol, NULL));
297d0609cedSBarry Smith   PetscOptionsHeadEnd();
2983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2992d3f70b5SBarry Smith }
3002d3f70b5SBarry Smith 
TSView_Pseudo(TS ts,PetscViewer viewer)301d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSView_Pseudo(TS ts, PetscViewer viewer)
302d71ae5a4SJacob Faibussowitsch {
3033118ae5eSBarry Smith   PetscBool isascii;
304d52bd9f3SBarry Smith 
3053a40ed3dSBarry Smith   PetscFunctionBegin;
3069566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
3073118ae5eSBarry Smith   if (isascii) {
3083118ae5eSBarry Smith     TS_Pseudo *pseudo = (TS_Pseudo *)ts->data;
3099566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  frtol - relative tolerance in function value %g\n", (double)pseudo->frtol));
3109566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  fatol - absolute tolerance in function value %g\n", (double)pseudo->fatol));
3119566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  dt_initial - initial timestep %g\n", (double)pseudo->dt_initial));
3129566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  dt_increment - increase in timestep on successful step %g\n", (double)pseudo->dt_increment));
3139566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  dt_max - maximum time %g\n", (double)pseudo->dt_max));
3143118ae5eSBarry Smith   }
3153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3162d3f70b5SBarry Smith }
3172d3f70b5SBarry Smith 
318ac226902SBarry Smith /*@C
319c558785fSJames Wright   TSPseudoTimeStepDefault - Default code to compute pseudo-timestepping.  Use with `TSPseudoSetTimeStep()`.
320c558785fSJames Wright 
321c558785fSJames Wright   Collective, No Fortran Support
322c558785fSJames Wright 
323c558785fSJames Wright   Input Parameters:
324c558785fSJames Wright + ts    - the timestep context
325c558785fSJames Wright - dtctx - unused timestep context
326c558785fSJames Wright 
327c558785fSJames Wright   Output Parameter:
328c558785fSJames Wright . newdt - the timestep to use for the next step
329c558785fSJames Wright 
330c558785fSJames Wright   Level: advanced
331c558785fSJames Wright 
332c558785fSJames Wright .seealso: [](ch_ts), `TSPseudoSetTimeStep()`, `TSPseudoComputeTimeStep()`, `TSPSEUDO`
333c558785fSJames Wright @*/
TSPseudoTimeStepDefault(TS ts,PetscReal * newdt,void * dtctx)334c558785fSJames Wright PetscErrorCode TSPseudoTimeStepDefault(TS ts, PetscReal *newdt, void *dtctx)
335c558785fSJames Wright {
336c558785fSJames Wright   TS_Pseudo *pseudo = (TS_Pseudo *)ts->data;
3370fe2f5c2SJames Wright   PetscReal  inc    = pseudo->dt_increment, fnorm;
338c558785fSJames Wright 
339c558785fSJames Wright   PetscFunctionBegin;
3400fe2f5c2SJames Wright   PetscCall(TSPseudoComputeFunction(ts, ts->vec_sol, NULL, &fnorm));
341c558785fSJames Wright   if (pseudo->fnorm_initial < 0) {
342c558785fSJames Wright     /* first time through so compute initial function norm */
3430fe2f5c2SJames Wright     pseudo->fnorm_initial  = fnorm;
3440fe2f5c2SJames Wright     pseudo->fnorm_previous = fnorm;
345c558785fSJames Wright   }
3460fe2f5c2SJames Wright   if (fnorm == 0.0) *newdt = 1.e12 * inc * ts->time_step;
3470fe2f5c2SJames Wright   else if (pseudo->increment_dt_from_initial_dt) *newdt = inc * pseudo->dt_initial * pseudo->fnorm_initial / fnorm;
3480fe2f5c2SJames Wright   else *newdt = inc * ts->time_step * pseudo->fnorm_previous / fnorm;
349c558785fSJames Wright   if (pseudo->dt_max > 0) *newdt = PetscMin(*newdt, pseudo->dt_max);
3500fe2f5c2SJames Wright   pseudo->fnorm_previous = fnorm;
351c558785fSJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
352c558785fSJames Wright }
353c558785fSJames Wright 
TSAdaptChoose_TSPseudo(TSAdapt adapt,TS ts,PetscReal h,PetscInt * next_sc,PetscReal * next_h,PetscBool * accept,PetscReal * wlte,PetscReal * wltea,PetscReal * wlter)354c558785fSJames Wright static PetscErrorCode TSAdaptChoose_TSPseudo(TSAdapt adapt, TS ts, PetscReal h, PetscInt *next_sc, PetscReal *next_h, PetscBool *accept, PetscReal *wlte, PetscReal *wltea, PetscReal *wlter)
355c558785fSJames Wright {
356c558785fSJames Wright   TS_Pseudo *pseudo = (TS_Pseudo *)ts->data;
357c558785fSJames Wright 
358c558785fSJames Wright   PetscFunctionBegin;
359c558785fSJames Wright   PetscCall(PetscLogEventBegin(TS_PseudoComputeTimeStep, ts, 0, 0, 0));
360f6ceb9cfSJames Wright   PetscCallBack("TSPSEUDO callback time step", (*pseudo->dt)(ts, next_h, pseudo->dtctx));
361c558785fSJames Wright   PetscCall(PetscLogEventEnd(TS_PseudoComputeTimeStep, ts, 0, 0, 0));
362c558785fSJames Wright 
363c558785fSJames Wright   *next_sc = 0;
364c558785fSJames Wright   *wlte    = -1; /* Weighted local truncation error was not evaluated */
365c558785fSJames Wright   *wltea   = -1; /* Weighted absolute local truncation error was not evaluated */
366c558785fSJames Wright   *wlter   = -1; /* Weighted relative local truncation error was not evaluated */
367c558785fSJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
368c558785fSJames Wright }
369c558785fSJames Wright 
TSAdaptCheckStage_TSPseudo(TSAdapt adapt,TS ts,PetscReal t,Vec Y,PetscBool * accept)370c558785fSJames Wright static PetscErrorCode TSAdaptCheckStage_TSPseudo(TSAdapt adapt, TS ts, PetscReal t, Vec Y, PetscBool *accept)
371c558785fSJames Wright {
372c558785fSJames Wright   TS_Pseudo *pseudo = (TS_Pseudo *)ts->data;
373c558785fSJames Wright 
374c558785fSJames Wright   PetscFunctionBegin;
375c558785fSJames Wright   if (pseudo->verify) {
376c558785fSJames Wright     PetscReal dt;
377c558785fSJames Wright     PetscCall(TSGetTimeStep(ts, &dt));
378f6ceb9cfSJames Wright     PetscCallBack("TSPSEUDO callback verify time step", (*pseudo->verify)(ts, Y, pseudo->verifyctx, &dt, accept));
379c558785fSJames Wright     PetscCall(TSSetTimeStep(ts, dt));
380c558785fSJames Wright   }
381c558785fSJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
382c558785fSJames Wright }
383c558785fSJames Wright 
384c558785fSJames Wright /*MC
385c558785fSJames Wright   TSADAPTTSPSEUDO - TSPseudo adaptive controller for time stepping
386c558785fSJames Wright 
387c558785fSJames Wright   Level: developer
388c558785fSJames Wright 
389c558785fSJames Wright   Note:
390c558785fSJames Wright   This is only meant to be used with `TSPSEUDO` time integrator.
391c558785fSJames Wright 
392c558785fSJames Wright .seealso: [](ch_ts), `TS`, `TSAdapt`, `TSGetAdapt()`, `TSAdaptType`, `TSPSEUDO`
393c558785fSJames Wright M*/
TSAdaptCreate_TSPseudo(TSAdapt adapt)394c558785fSJames Wright static PetscErrorCode TSAdaptCreate_TSPseudo(TSAdapt adapt)
395c558785fSJames Wright {
396c558785fSJames Wright   PetscFunctionBegin;
397c558785fSJames Wright   adapt->ops->choose = TSAdaptChoose_TSPseudo;
398c558785fSJames Wright   adapt->checkstage  = TSAdaptCheckStage_TSPseudo;
399c558785fSJames Wright   PetscFunctionReturn(PETSC_SUCCESS);
400c558785fSJames Wright }
401c558785fSJames Wright 
402c558785fSJames Wright /*@C
40382bf6240SBarry Smith   TSPseudoSetVerifyTimeStep - Sets a user-defined routine to verify the quality of the
40482bf6240SBarry Smith   last timestep.
40582bf6240SBarry Smith 
406c3339decSBarry Smith   Logically Collective
40715091d37SBarry Smith 
40882bf6240SBarry Smith   Input Parameters:
40915091d37SBarry Smith + ts  - timestep context
41082bf6240SBarry Smith . dt  - user-defined function to verify timestep
4112fe279fdSBarry Smith - ctx - [optional] user-defined context for private data for the timestep verification routine (may be `NULL`)
41282bf6240SBarry Smith 
41320f4b53cSBarry Smith   Calling sequence of `func`:
4142fe279fdSBarry Smith + ts     - the time-step context
4152fe279fdSBarry Smith . update - latest solution vector
41614d0ab18SJacob Faibussowitsch . ctx    - [optional] user-defined timestep context
41782bf6240SBarry Smith . newdt  - the timestep to use for the next step
418a2b725a8SWilliam Gropp - flag   - flag indicating whether the last time step was acceptable
41982bf6240SBarry Smith 
420bcf0153eSBarry Smith   Level: advanced
421bcf0153eSBarry Smith 
422bcf0153eSBarry Smith   Note:
423bcf0153eSBarry Smith   The routine set here will be called by `TSPseudoVerifyTimeStep()`
42482bf6240SBarry Smith   during the timestepping process.
42582bf6240SBarry Smith 
4261cc06b55SBarry Smith .seealso: [](ch_ts), `TSPSEUDO`, `TSPseudoVerifyTimeStepDefault()`, `TSPseudoVerifyTimeStep()`
42782bf6240SBarry Smith @*/
TSPseudoSetVerifyTimeStep(TS ts,PetscErrorCode (* dt)(TS ts,Vec update,PetscCtx ctx,PetscReal * newdt,PetscBool * flag),PetscCtx ctx)428*2a8381b2SBarry Smith PetscErrorCode TSPseudoSetVerifyTimeStep(TS ts, PetscErrorCode (*dt)(TS ts, Vec update, PetscCtx ctx, PetscReal *newdt, PetscBool *flag), PetscCtx ctx)
429d71ae5a4SJacob Faibussowitsch {
43082bf6240SBarry Smith   PetscFunctionBegin;
4310700a824SBarry Smith   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
432cac4c232SBarry Smith   PetscTryMethod(ts, "TSPseudoSetVerifyTimeStep_C", (TS, PetscErrorCode (*)(TS, Vec, void *, PetscReal *, PetscBool *), void *), (ts, dt, ctx));
4333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
43482bf6240SBarry Smith }
43582bf6240SBarry Smith 
43682bf6240SBarry Smith /*@
43782bf6240SBarry Smith   TSPseudoSetTimeStepIncrement - Sets the scaling increment applied to
4388d359177SBarry Smith   dt when using the TSPseudoTimeStepDefault() routine.
43982bf6240SBarry Smith 
440c3339decSBarry Smith   Logically Collective
441fee21e36SBarry Smith 
44215091d37SBarry Smith   Input Parameters:
44315091d37SBarry Smith + ts  - the timestep context
44415091d37SBarry Smith - inc - the scaling factor >= 1.0
44515091d37SBarry Smith 
44682bf6240SBarry Smith   Options Database Key:
44767b8a455SSatish Balay . -ts_pseudo_increment <increment> - set pseudo increment
44882bf6240SBarry Smith 
44915091d37SBarry Smith   Level: advanced
45015091d37SBarry Smith 
4511cc06b55SBarry Smith .seealso: [](ch_ts), `TSPSEUDO`, `TSPseudoSetTimeStep()`, `TSPseudoTimeStepDefault()`
45282bf6240SBarry Smith @*/
TSPseudoSetTimeStepIncrement(TS ts,PetscReal inc)453d71ae5a4SJacob Faibussowitsch PetscErrorCode TSPseudoSetTimeStepIncrement(TS ts, PetscReal inc)
454d71ae5a4SJacob Faibussowitsch {
45582bf6240SBarry Smith   PetscFunctionBegin;
4560700a824SBarry Smith   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
457c5eb9154SBarry Smith   PetscValidLogicalCollectiveReal(ts, inc, 2);
458cac4c232SBarry Smith   PetscTryMethod(ts, "TSPseudoSetTimeStepIncrement_C", (TS, PetscReal), (ts, inc));
4593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
46082bf6240SBarry Smith }
46182bf6240SBarry Smith 
46286534af1SJed Brown /*@
46386534af1SJed Brown   TSPseudoSetMaxTimeStep - Sets the maximum time step
4648d359177SBarry Smith   when using the TSPseudoTimeStepDefault() routine.
46586534af1SJed Brown 
466c3339decSBarry Smith   Logically Collective
46786534af1SJed Brown 
46886534af1SJed Brown   Input Parameters:
46986534af1SJed Brown + ts    - the timestep context
47086534af1SJed Brown - maxdt - the maximum time step, use a non-positive value to deactivate
47186534af1SJed Brown 
47286534af1SJed Brown   Options Database Key:
47367b8a455SSatish Balay . -ts_pseudo_max_dt <increment> - set pseudo max dt
47486534af1SJed Brown 
47586534af1SJed Brown   Level: advanced
47686534af1SJed Brown 
4771cc06b55SBarry Smith .seealso: [](ch_ts), `TSPSEUDO`, `TSPseudoSetTimeStep()`, `TSPseudoTimeStepDefault()`
47886534af1SJed Brown @*/
TSPseudoSetMaxTimeStep(TS ts,PetscReal maxdt)479d71ae5a4SJacob Faibussowitsch PetscErrorCode TSPseudoSetMaxTimeStep(TS ts, PetscReal maxdt)
480d71ae5a4SJacob Faibussowitsch {
48186534af1SJed Brown   PetscFunctionBegin;
48286534af1SJed Brown   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
48386534af1SJed Brown   PetscValidLogicalCollectiveReal(ts, maxdt, 2);
484cac4c232SBarry Smith   PetscTryMethod(ts, "TSPseudoSetMaxTimeStep_C", (TS, PetscReal), (ts, maxdt));
4853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
48686534af1SJed Brown }
48786534af1SJed Brown 
48882bf6240SBarry Smith /*@
48982bf6240SBarry Smith   TSPseudoIncrementDtFromInitialDt - Indicates that a new timestep
490b44f4de4SBarry Smith   is computed via the formula $  dt = initial\_dt*initial\_fnorm/current\_fnorm $  rather than the default update, $  dt = current\_dt*previous\_fnorm/current\_fnorm.$
49182bf6240SBarry Smith 
492c3339decSBarry Smith   Logically Collective
49315091d37SBarry Smith 
49482bf6240SBarry Smith   Input Parameter:
49582bf6240SBarry Smith . ts - the timestep context
49682bf6240SBarry Smith 
49782bf6240SBarry Smith   Options Database Key:
498b44f4de4SBarry Smith . -ts_pseudo_increment_dt_from_initial_dt <true,false> - use the initial $dt$ to determine increment
49982bf6240SBarry Smith 
50015091d37SBarry Smith   Level: advanced
50115091d37SBarry Smith 
5021cc06b55SBarry Smith .seealso: [](ch_ts), `TSPSEUDO`, `TSPseudoSetTimeStep()`, `TSPseudoTimeStepDefault()`
50382bf6240SBarry Smith @*/
TSPseudoIncrementDtFromInitialDt(TS ts)504d71ae5a4SJacob Faibussowitsch PetscErrorCode TSPseudoIncrementDtFromInitialDt(TS ts)
505d71ae5a4SJacob Faibussowitsch {
50682bf6240SBarry Smith   PetscFunctionBegin;
5070700a824SBarry Smith   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
508cac4c232SBarry Smith   PetscTryMethod(ts, "TSPseudoIncrementDtFromInitialDt_C", (TS), (ts));
5093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
51082bf6240SBarry Smith }
51182bf6240SBarry Smith 
512ac226902SBarry Smith /*@C
51382bf6240SBarry Smith   TSPseudoSetTimeStep - Sets the user-defined routine to be
51482bf6240SBarry Smith   called at each pseudo-timestep to update the timestep.
51582bf6240SBarry Smith 
516c3339decSBarry Smith   Logically Collective
51715091d37SBarry Smith 
51882bf6240SBarry Smith   Input Parameters:
51915091d37SBarry Smith + ts  - timestep context
52082bf6240SBarry Smith . dt  - function to compute timestep
5212fe279fdSBarry Smith - ctx - [optional] user-defined context for private data required by the function (may be `NULL`)
52282bf6240SBarry Smith 
52320f4b53cSBarry Smith   Calling sequence of `dt`:
52414d0ab18SJacob Faibussowitsch + ts    - the `TS` context
52514d0ab18SJacob Faibussowitsch . newdt - the newly computed timestep
52614d0ab18SJacob Faibussowitsch - ctx   - [optional] user-defined context
52782bf6240SBarry Smith 
528bcf0153eSBarry Smith   Level: intermediate
52982bf6240SBarry Smith 
530bcf0153eSBarry Smith   Notes:
531bcf0153eSBarry Smith   The routine set here will be called by `TSPseudoComputeTimeStep()`
532bcf0153eSBarry Smith   during the timestepping process.
533bcf0153eSBarry Smith 
534bcf0153eSBarry Smith   If not set then `TSPseudoTimeStepDefault()` is automatically used
535bcf0153eSBarry Smith 
5361cc06b55SBarry Smith .seealso: [](ch_ts), `TSPSEUDO`, `TSPseudoTimeStepDefault()`, `TSPseudoComputeTimeStep()`
53782bf6240SBarry Smith @*/
TSPseudoSetTimeStep(TS ts,PetscErrorCode (* dt)(TS ts,PetscReal * newdt,PetscCtx ctx),PetscCtx ctx)538*2a8381b2SBarry Smith PetscErrorCode TSPseudoSetTimeStep(TS ts, PetscErrorCode (*dt)(TS ts, PetscReal *newdt, PetscCtx ctx), PetscCtx ctx)
539d71ae5a4SJacob Faibussowitsch {
54082bf6240SBarry Smith   PetscFunctionBegin;
5410700a824SBarry Smith   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
542cac4c232SBarry Smith   PetscTryMethod(ts, "TSPseudoSetTimeStep_C", (TS, PetscErrorCode (*)(TS, PetscReal *, void *), void *), (ts, dt, ctx));
5433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
54482bf6240SBarry Smith }
54582bf6240SBarry Smith 
546ace3abfcSBarry Smith typedef PetscErrorCode (*FCN1)(TS, Vec, void *, PetscReal *, PetscBool *); /* force argument to next function to not be extern C*/
TSPseudoSetVerifyTimeStep_Pseudo(TS ts,FCN1 dt,PetscCtx ctx)547*2a8381b2SBarry Smith static PetscErrorCode TSPseudoSetVerifyTimeStep_Pseudo(TS ts, FCN1 dt, PetscCtx ctx)
548d71ae5a4SJacob Faibussowitsch {
549be5899b3SLisandro Dalcin   TS_Pseudo *pseudo = (TS_Pseudo *)ts->data;
55082bf6240SBarry Smith 
55182bf6240SBarry Smith   PetscFunctionBegin;
55282bf6240SBarry Smith   pseudo->verify    = dt;
55382bf6240SBarry Smith   pseudo->verifyctx = ctx;
5543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
55582bf6240SBarry Smith }
55682bf6240SBarry Smith 
TSPseudoSetTimeStepIncrement_Pseudo(TS ts,PetscReal inc)557d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSPseudoSetTimeStepIncrement_Pseudo(TS ts, PetscReal inc)
558d71ae5a4SJacob Faibussowitsch {
5594bbc92c1SBarry Smith   TS_Pseudo *pseudo = (TS_Pseudo *)ts->data;
56082bf6240SBarry Smith 
56182bf6240SBarry Smith   PetscFunctionBegin;
56282bf6240SBarry Smith   pseudo->dt_increment = inc;
5633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
56482bf6240SBarry Smith }
56582bf6240SBarry Smith 
TSPseudoSetMaxTimeStep_Pseudo(TS ts,PetscReal maxdt)566d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSPseudoSetMaxTimeStep_Pseudo(TS ts, PetscReal maxdt)
567d71ae5a4SJacob Faibussowitsch {
56886534af1SJed Brown   TS_Pseudo *pseudo = (TS_Pseudo *)ts->data;
56986534af1SJed Brown 
57086534af1SJed Brown   PetscFunctionBegin;
57186534af1SJed Brown   pseudo->dt_max = maxdt;
5723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
57386534af1SJed Brown }
57486534af1SJed Brown 
TSPseudoIncrementDtFromInitialDt_Pseudo(TS ts)575d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSPseudoIncrementDtFromInitialDt_Pseudo(TS ts)
576d71ae5a4SJacob Faibussowitsch {
5774bbc92c1SBarry Smith   TS_Pseudo *pseudo = (TS_Pseudo *)ts->data;
57882bf6240SBarry Smith 
57982bf6240SBarry Smith   PetscFunctionBegin;
5804bbc92c1SBarry Smith   pseudo->increment_dt_from_initial_dt = PETSC_TRUE;
5813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
58282bf6240SBarry Smith }
58382bf6240SBarry Smith 
5846849ba73SBarry Smith typedef PetscErrorCode (*FCN2)(TS, PetscReal *, void *); /* force argument to next function to not be extern C*/
TSPseudoSetTimeStep_Pseudo(TS ts,FCN2 dt,PetscCtx ctx)585*2a8381b2SBarry Smith static PetscErrorCode TSPseudoSetTimeStep_Pseudo(TS ts, FCN2 dt, PetscCtx ctx)
586d71ae5a4SJacob Faibussowitsch {
5874bbc92c1SBarry Smith   TS_Pseudo *pseudo = (TS_Pseudo *)ts->data;
58882bf6240SBarry Smith 
58982bf6240SBarry Smith   PetscFunctionBegin;
59082bf6240SBarry Smith   pseudo->dt    = dt;
59182bf6240SBarry Smith   pseudo->dtctx = ctx;
5923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
59382bf6240SBarry Smith }
59482bf6240SBarry Smith 
59510e6a065SJed Brown /*MC
5961d27aa22SBarry Smith   TSPSEUDO - Solve steady state ODE and DAE problems with pseudo time stepping {cite}`ckk02` {cite}`kk97`
59782bf6240SBarry Smith 
59810e6a065SJed Brown   This method solves equations of the form
59910e6a065SJed Brown 
6001d27aa22SBarry Smith   $$
6011d27aa22SBarry Smith   F(X,Xdot) = 0
6021d27aa22SBarry Smith   $$
60310e6a065SJed Brown 
60410e6a065SJed Brown   for steady state using the iteration
60510e6a065SJed Brown 
6061d27aa22SBarry Smith   $$
60737fdd005SBarry Smith   [G'] S = -F(X,0)
60837fdd005SBarry Smith   X += S
6091d27aa22SBarry Smith   $$
61010e6a065SJed Brown 
61110e6a065SJed Brown   where
61210e6a065SJed Brown 
6131d27aa22SBarry Smith   $$
6141d27aa22SBarry Smith   G(Y) = F(Y,(Y-X)/dt)
6151d27aa22SBarry Smith   $$
61610e6a065SJed Brown 
6176f2d6a7bSJed Brown   This is linearly-implicit Euler with the residual always evaluated "at steady
6186f2d6a7bSJed Brown   state".  See note below.
61910e6a065SJed Brown 
62093a54799SPierre Jolivet   In addition to the modified solve, a dedicated adaptive timestepping scheme is implemented, mimicking the switched evolution relaxation in {cite}`ckk02`.
621fb59f417SJames Wright   It determines the next timestep via
622fb59f417SJames Wright 
623fb59f417SJames Wright   $$
624fb59f417SJames Wright   dt_{n} = r dt_{n-1} \frac{\Vert F(X_{n},0) \Vert}{\Vert F(X_{n-1},0) \Vert}
625fb59f417SJames Wright   $$
626fb59f417SJames Wright 
627fb59f417SJames Wright   where $r$ is an additional growth factor (set by `-ts_pseudo_increment`).
628fb59f417SJames Wright   An alternative formulation is also available that uses the initial timestep and function norm.
629fb59f417SJames Wright 
630fb59f417SJames Wright   $$
631fb59f417SJames Wright   dt_{n} = r dt_{0} \frac{\Vert F(X_{n},0) \Vert}{\Vert F(X_{0},0) \Vert}
632fb59f417SJames Wright   $$
633fb59f417SJames Wright 
634fb59f417SJames Wright   This is chosen by setting `-ts_pseudo_increment_dt_from_initial_dt`.
635fb59f417SJames Wright   For either method, an upper limit on the timestep can be set by `-ts_pseudo_max_dt`.
636fb59f417SJames Wright 
637bcf0153eSBarry Smith   Options Database Keys:
63810e6a065SJed Brown +  -ts_pseudo_increment <real>                     - ratio of increase dt
6393118ae5eSBarry Smith .  -ts_pseudo_increment_dt_from_initial_dt <truth> - Increase dt as a ratio from original dt
640fb59f417SJames Wright .  -ts_pseudo_max_dt                               - Maximum dt for adaptive timestepping algorithm
641fb59f417SJames Wright .  -ts_pseudo_monitor                              - Monitor convergence of the function norm
642fb59f417SJames Wright .  -ts_pseudo_fatol <atol>                         - stop iterating when the function norm is less than `atol`
643fb59f417SJames Wright -  -ts_pseudo_frtol <rtol>                         - stop iterating when the function norm divided by the initial function norm is less than `rtol`
64410e6a065SJed Brown 
64510e6a065SJed Brown   Level: beginner
64610e6a065SJed Brown 
64710e6a065SJed Brown   Notes:
6486f2d6a7bSJed Brown   The residual computed by this method includes the transient term (Xdot is computed instead of
6496f2d6a7bSJed Brown   always being zero), but since the prediction from the last step is always the solution from the
6506f2d6a7bSJed Brown   last step, on the first Newton iteration we have
6516f2d6a7bSJed Brown 
6521d27aa22SBarry Smith   $$
6531d27aa22SBarry Smith   Xdot = (Xpredicted - Xold)/dt = (Xold-Xold)/dt = 0
6541d27aa22SBarry Smith   $$
6556f2d6a7bSJed Brown 
656eb636060SBarry Smith   The Jacobian $ dF/dX + shift*dF/dXdot $ contains a non-zero $ dF/dXdot$ term. In the $ X' = F(X) $ case it
657eb636060SBarry Smith   is $ dF/dX + shift*1/dt $. Hence  still contains the $ 1/dt $ term so the Jacobian is not simply the
658eb636060SBarry Smith   Jacobian of $ F $ and thus this pseudo-transient continuation is not just Newton on $F(x)=0$.
659eb636060SBarry Smith 
6606f2d6a7bSJed Brown   Therefore, the linear system solved by the first Newton iteration is equivalent to the one
6616f2d6a7bSJed Brown   described above and in the papers.  If the user chooses to perform multiple Newton iterations, the
6626f2d6a7bSJed Brown   algorithm is no longer the one described in the referenced papers.
663fb59f417SJames Wright   By default, the `SNESType` is set to `SNESKSPONLY` to match the algorithm from the referenced papers.
664fb59f417SJames Wright   Setting the `SNESType` via `-snes_type` will override this default setting.
66510e6a065SJed Brown 
6661cc06b55SBarry Smith .seealso: [](ch_ts), `TSCreate()`, `TS`, `TSSetType()`
66710e6a065SJed Brown M*/
TSCreate_Pseudo(TS ts)668d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode TSCreate_Pseudo(TS ts)
669d71ae5a4SJacob Faibussowitsch {
6707bf11e45SBarry Smith   TS_Pseudo *pseudo;
671193ac0bcSJed Brown   SNES       snes;
67219fd82e9SBarry Smith   SNESType   stype;
6732d3f70b5SBarry Smith 
6743a40ed3dSBarry Smith   PetscFunctionBegin;
675277b19d0SLisandro Dalcin   ts->ops->reset          = TSReset_Pseudo;
676000e7ae3SMatthew Knepley   ts->ops->destroy        = TSDestroy_Pseudo;
677000e7ae3SMatthew Knepley   ts->ops->view           = TSView_Pseudo;
678000e7ae3SMatthew Knepley   ts->ops->setup          = TSSetUp_Pseudo;
679000e7ae3SMatthew Knepley   ts->ops->step           = TSStep_Pseudo;
680000e7ae3SMatthew Knepley   ts->ops->setfromoptions = TSSetFromOptions_Pseudo;
6810f5c6efeSJed Brown   ts->ops->snesfunction   = SNESTSFormFunction_Pseudo;
6820f5c6efeSJed Brown   ts->ops->snesjacobian   = SNESTSFormJacobian_Pseudo;
683c558785fSJames Wright   ts->default_adapt_type  = TSADAPTTSPSEUDO;
684825ab935SBarry Smith   ts->usessnes            = PETSC_TRUE;
6857bf11e45SBarry Smith 
686c558785fSJames Wright   PetscCall(TSAdaptRegister(TSADAPTTSPSEUDO, TSAdaptCreate_TSPseudo));
687c558785fSJames Wright 
6889566063dSJacob Faibussowitsch   PetscCall(TSGetSNES(ts, &snes));
6899566063dSJacob Faibussowitsch   PetscCall(SNESGetType(snes, &stype));
6909566063dSJacob Faibussowitsch   if (!stype) PetscCall(SNESSetType(snes, SNESKSPONLY));
6912d3f70b5SBarry Smith 
6924dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&pseudo));
6937bf11e45SBarry Smith   ts->data = (void *)pseudo;
6942d3f70b5SBarry Smith 
695be5899b3SLisandro Dalcin   pseudo->dt                           = TSPseudoTimeStepDefault;
696be5899b3SLisandro Dalcin   pseudo->dtctx                        = NULL;
69728aa8177SBarry Smith   pseudo->dt_increment                 = 1.1;
6984bbc92c1SBarry Smith   pseudo->increment_dt_from_initial_dt = PETSC_FALSE;
699193ac0bcSJed Brown   pseudo->fnorm                        = -1;
700be5899b3SLisandro Dalcin   pseudo->fnorm_initial                = -1;
701be5899b3SLisandro Dalcin   pseudo->fnorm_previous               = -1;
7023118ae5eSBarry Smith #if defined(PETSC_USE_REAL_SINGLE)
7033118ae5eSBarry Smith   pseudo->fatol = 1.e-25;
7043118ae5eSBarry Smith   pseudo->frtol = 1.e-5;
7053118ae5eSBarry Smith #else
7063118ae5eSBarry Smith   pseudo->fatol = 1.e-50;
7073118ae5eSBarry Smith   pseudo->frtol = 1.e-12;
7083118ae5eSBarry Smith #endif
7099566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSPseudoSetVerifyTimeStep_C", TSPseudoSetVerifyTimeStep_Pseudo));
7109566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSPseudoSetTimeStepIncrement_C", TSPseudoSetTimeStepIncrement_Pseudo));
7119566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSPseudoSetMaxTimeStep_C", TSPseudoSetMaxTimeStep_Pseudo));
7129566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSPseudoIncrementDtFromInitialDt_C", TSPseudoIncrementDtFromInitialDt_Pseudo));
7139566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)ts, "TSPseudoSetTimeStep_C", TSPseudoSetTimeStep_Pseudo));
7143ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7152d3f70b5SBarry Smith }
716