xref: /petsc/src/ts/event/tsevent.c (revision 9b3d37595c38021c4a8c83d4afb469cc90373e62)
1af0996ceSBarry Smith #include <petsc/private/tsimpl.h> /*I  "petscts.h" I*/
22dc7a7e3SShri Abhyankar 
36fea3669SShri Abhyankar /*
46427ac75SLisandro Dalcin   TSEventInitialize - Initializes TSEvent for TSSolve
56fea3669SShri Abhyankar */
6d71ae5a4SJacob Faibussowitsch PetscErrorCode TSEventInitialize(TSEvent event, TS ts, PetscReal t, Vec U)
7d71ae5a4SJacob Faibussowitsch {
86fea3669SShri Abhyankar   PetscFunctionBegin;
93ba16761SJacob Faibussowitsch   if (!event) PetscFunctionReturn(PETSC_SUCCESS);
104f572ea9SToby Isaac   PetscAssertPointer(event, 1);
116427ac75SLisandro Dalcin   PetscValidHeaderSpecific(ts, TS_CLASSID, 2);
126427ac75SLisandro Dalcin   PetscValidHeaderSpecific(U, VEC_CLASSID, 4);
136fea3669SShri Abhyankar   event->ptime_prev = t;
1438bf2713SShri Abhyankar   event->iterctr    = 0;
15*9b3d3759SBarry Smith   PetscCall((*event->indicator)(ts, t, U, event->fvalue_prev, event->ctx));
163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
176fea3669SShri Abhyankar }
186fea3669SShri Abhyankar 
19d71ae5a4SJacob Faibussowitsch PetscErrorCode TSEventDestroy(TSEvent *event)
20d71ae5a4SJacob Faibussowitsch {
217dbe0728SLisandro Dalcin   PetscInt i;
227dbe0728SLisandro Dalcin 
237dbe0728SLisandro Dalcin   PetscFunctionBegin;
244f572ea9SToby Isaac   PetscAssertPointer(event, 1);
253ba16761SJacob Faibussowitsch   if (!*event) PetscFunctionReturn(PETSC_SUCCESS);
269371c9d4SSatish Balay   if (--(*event)->refct > 0) {
279371c9d4SSatish Balay     *event = NULL;
283ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
299371c9d4SSatish Balay   }
30e7069c78SShri 
319566063dSJacob Faibussowitsch   PetscCall(PetscFree((*event)->fvalue));
329566063dSJacob Faibussowitsch   PetscCall(PetscFree((*event)->fvalue_prev));
339566063dSJacob Faibussowitsch   PetscCall(PetscFree((*event)->fvalue_right));
349566063dSJacob Faibussowitsch   PetscCall(PetscFree((*event)->zerocrossing));
359566063dSJacob Faibussowitsch   PetscCall(PetscFree((*event)->side));
369566063dSJacob Faibussowitsch   PetscCall(PetscFree((*event)->direction));
379566063dSJacob Faibussowitsch   PetscCall(PetscFree((*event)->terminate));
389566063dSJacob Faibussowitsch   PetscCall(PetscFree((*event)->events_zero));
399566063dSJacob Faibussowitsch   PetscCall(PetscFree((*event)->vtol));
40a4ffd976SShri Abhyankar 
4148a46eb9SPierre Jolivet   for (i = 0; i < (*event)->recsize; i++) PetscCall(PetscFree((*event)->recorder.eventidx[i]));
429566063dSJacob Faibussowitsch   PetscCall(PetscFree((*event)->recorder.eventidx));
439566063dSJacob Faibussowitsch   PetscCall(PetscFree((*event)->recorder.nevents));
449566063dSJacob Faibussowitsch   PetscCall(PetscFree((*event)->recorder.stepnum));
459566063dSJacob Faibussowitsch   PetscCall(PetscFree((*event)->recorder.time));
46a4ffd976SShri Abhyankar 
479566063dSJacob Faibussowitsch   PetscCall(PetscViewerDestroy(&(*event)->monitor));
489566063dSJacob Faibussowitsch   PetscCall(PetscFree(*event));
493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
507dbe0728SLisandro Dalcin }
517dbe0728SLisandro Dalcin 
52e3005195SShri Abhyankar /*@
5320f4b53cSBarry Smith   TSSetPostEventIntervalStep - Set the time-step used immediately following an event interval
54458122a4SShri Abhyankar 
55458122a4SShri Abhyankar   Logically Collective
56458122a4SShri Abhyankar 
574165533cSJose E. Roman   Input Parameters:
58458122a4SShri Abhyankar + ts - time integration context
59*9b3d3759SBarry Smith - dt - post-event interval step
60458122a4SShri Abhyankar 
61bcf0153eSBarry Smith   Options Database Key:
62b43aa488SJacob Faibussowitsch . -ts_event_post_eventinterval_step <dt> - time-step after event interval
63458122a4SShri Abhyankar 
64bcf0153eSBarry Smith   Level: advanced
65458122a4SShri Abhyankar 
66bcf0153eSBarry Smith   Notes:
67bcf0153eSBarry Smith   `TSSetPostEventIntervalStep()` allows one to set a time-step that is used immediately following an event interval.
68bcf0153eSBarry Smith 
69*9b3d3759SBarry Smith   This function should be called from the post-event function set with `TSSetEventHandler()`.
70458122a4SShri Abhyankar 
71*9b3d3759SBarry Smith   The post-event interval time-step should be selected based on the dynamics following the event.
72458122a4SShri Abhyankar   If the dynamics are stiff, a conservative (small) step should be used.
73458122a4SShri Abhyankar   If not, then a larger time-step can be used.
74458122a4SShri Abhyankar 
751cc06b55SBarry Smith .seealso: [](ch_ts), `TS`, `TSEvent`, `TSSetEventHandler()`
76458122a4SShri Abhyankar @*/
77d71ae5a4SJacob Faibussowitsch PetscErrorCode TSSetPostEventIntervalStep(TS ts, PetscReal dt)
78d71ae5a4SJacob Faibussowitsch {
79458122a4SShri Abhyankar   PetscFunctionBegin;
80458122a4SShri Abhyankar   ts->event->timestep_posteventinterval = dt;
813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
82458122a4SShri Abhyankar }
83458122a4SShri Abhyankar 
84458122a4SShri Abhyankar /*@
8520f4b53cSBarry Smith   TSSetEventTolerances - Set tolerances for event zero crossings
86e3005195SShri Abhyankar 
87e3005195SShri Abhyankar   Logically Collective
88e3005195SShri Abhyankar 
894165533cSJose E. Roman   Input Parameters:
90e3005195SShri Abhyankar + ts   - time integration context
91bcf0153eSBarry Smith . tol  - scalar tolerance, `PETSC_DECIDE` to leave current value
92*9b3d3759SBarry Smith - vtol - array of tolerances or `NULL`, used in preference to `tol` if present
93e3005195SShri Abhyankar 
94bcf0153eSBarry Smith   Options Database Key:
95147403d9SBarry Smith . -ts_event_tol <tol> - tolerance for event zero crossing
96e3005195SShri Abhyankar 
97e3005195SShri Abhyankar   Level: beginner
98e3005195SShri Abhyankar 
99bcf0153eSBarry Smith   Notes:
100bcf0153eSBarry Smith   Must call `TSSetEventHandler(`) before setting the tolerances.
101bcf0153eSBarry Smith 
10220f4b53cSBarry Smith   The size of `vtol` is equal to the number of events.
10320f4b53cSBarry Smith 
10420f4b53cSBarry Smith   The tolerance is some measure of how close the event function is to zero for the event detector to stop
10520f4b53cSBarry Smith   and declare the time of the event has been detected.
106bcf0153eSBarry Smith 
1071cc06b55SBarry Smith .seealso: [](ch_ts), `TS`, `TSEvent`, `TSSetEventHandler()`
108e3005195SShri Abhyankar @*/
109d71ae5a4SJacob Faibussowitsch PetscErrorCode TSSetEventTolerances(TS ts, PetscReal tol, PetscReal vtol[])
110d71ae5a4SJacob Faibussowitsch {
1116427ac75SLisandro Dalcin   TSEvent  event;
112e3005195SShri Abhyankar   PetscInt i;
113e3005195SShri Abhyankar 
114e3005195SShri Abhyankar   PetscFunctionBegin;
1156427ac75SLisandro Dalcin   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1164f572ea9SToby Isaac   if (vtol) PetscAssertPointer(vtol, 3);
1173c633725SBarry Smith   PetscCheck(ts->event, PetscObjectComm((PetscObject)ts), PETSC_ERR_USER, "Must set the events first by calling TSSetEventHandler()");
1186427ac75SLisandro Dalcin 
1196427ac75SLisandro Dalcin   event = ts->event;
120e3005195SShri Abhyankar   if (vtol) {
121e3005195SShri Abhyankar     for (i = 0; i < event->nevents; i++) event->vtol[i] = vtol[i];
122e3005195SShri Abhyankar   } else {
123f3fa974cSJacob Faibussowitsch     if ((tol != (PetscReal)PETSC_DECIDE) || (tol != (PetscReal)PETSC_DEFAULT)) {
124e3005195SShri Abhyankar       for (i = 0; i < event->nevents; i++) event->vtol[i] = tol;
125e3005195SShri Abhyankar     }
126e3005195SShri Abhyankar   }
1273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
128e3005195SShri Abhyankar }
129e3005195SShri Abhyankar 
1302dc7a7e3SShri Abhyankar /*@C
131*9b3d3759SBarry Smith   TSSetEventHandler - Sets functions used for indicating event locations and handling them
1322dc7a7e3SShri Abhyankar 
133c3339decSBarry Smith   Logically Collective
1342dc7a7e3SShri Abhyankar 
1352dc7a7e3SShri Abhyankar   Input Parameters:
136bcf0153eSBarry Smith + ts        - the `TS` context obtained from `TSCreate()`
1372dc7a7e3SShri Abhyankar . nevents   - number of local events
138d94325d3SShri Abhyankar . direction - direction of zero crossing to be detected. -1 => Zero crossing in negative direction,
13914d0ab18SJacob Faibussowitsch                  0.1 => Zero crossing in positive direction, 0 => both ways (one for each event)
140*9b3d3759SBarry Smith . terminate - flag to indicate whether time stepping should be terminated after an event is detected (one for each event)
141*9b3d3759SBarry Smith . indicator - a change in sign of this function (see `direction`) is used to determine an event has occurred
14220f4b53cSBarry Smith . postevent - [optional] post-event function, this function can change properties of the solution, ODE etc at the time of the event
143*9b3d3759SBarry Smith - ctx       - [optional] user-defined context for private data for the indicator and post-event routine (use `NULL` if no context is desired)
1442dc7a7e3SShri Abhyankar 
145*9b3d3759SBarry Smith   Calling sequence of `indicator`:
1462fe279fdSBarry Smith + ts     - the `TS` context
1472dc7a7e3SShri Abhyankar . t      - current time
1482dc7a7e3SShri Abhyankar . U      - current iterate
149*9b3d3759SBarry Smith . fvalue - function value of events at time `t`
150*9b3d3759SBarry Smith - ctx    - the context passed as the final argument to `TSSetEventHandler()`
1512dc7a7e3SShri Abhyankar 
15220f4b53cSBarry Smith   Calling sequence of `postevent`:
1532fe279fdSBarry Smith + ts           - the `TS` context
15414d0ab18SJacob Faibussowitsch . nevents_zero - number of local events whose event function has been marked as crossing 0
15514d0ab18SJacob Faibussowitsch . events_zero  - indices of local events which have been marked as crossing 0
1562dc7a7e3SShri Abhyankar . t            - current time
1572dc7a7e3SShri Abhyankar . U            - current solution
1582fe279fdSBarry Smith . forwardsolve - Flag to indicate whether `TS` is doing a forward solve (1) or adjoint solve (0)
159*9b3d3759SBarry Smith - ctx          - the context passed as the final argument to `TSSetEventHandler()`
1602dc7a7e3SShri Abhyankar 
1612dc7a7e3SShri Abhyankar   Level: intermediate
1622dc7a7e3SShri Abhyankar 
1631cc06b55SBarry Smith .seealso: [](ch_ts), `TSEvent`, `TSCreate()`, `TSSetTimeStep()`, `TSSetConvergedReason()`
1642dc7a7e3SShri Abhyankar @*/
165*9b3d3759SBarry Smith PetscErrorCode TSSetEventHandler(TS ts, PetscInt nevents, PetscInt direction[], PetscBool terminate[], PetscErrorCode (*indicator)(TS ts, PetscReal t, Vec U, PetscScalar fvalue[], void *ctx), PetscErrorCode (*postevent)(TS ts, PetscInt nevents_zero, PetscInt events_zero[], PetscReal t, Vec U, PetscBool forwardsolve, void *ctx), void *ctx)
166d71ae5a4SJacob Faibussowitsch {
167d294eb03SHong Zhang   TSAdapt   adapt;
168d294eb03SHong Zhang   PetscReal hmin;
1692dc7a7e3SShri Abhyankar   TSEvent   event;
170d94325d3SShri Abhyankar   PetscInt  i;
171006e6a18SShri Abhyankar   PetscBool flg;
172a6c783d2SShri Abhyankar #if defined PETSC_USE_REAL_SINGLE
173a6c783d2SShri Abhyankar   PetscReal tol = 1e-4;
174a6c783d2SShri Abhyankar #else
175d569cc17SSatish Balay   PetscReal tol = 1e-6;
176a6c783d2SShri Abhyankar #endif
1772dc7a7e3SShri Abhyankar 
1782dc7a7e3SShri Abhyankar   PetscFunctionBegin;
1796427ac75SLisandro Dalcin   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1800a82b154SShri   if (nevents) {
1814f572ea9SToby Isaac     PetscAssertPointer(direction, 3);
1824f572ea9SToby Isaac     PetscAssertPointer(terminate, 4);
1830a82b154SShri   }
1846427ac75SLisandro Dalcin 
1854dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&event));
1869566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nevents, &event->fvalue));
1879566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nevents, &event->fvalue_prev));
1889566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nevents, &event->fvalue_right));
1899566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nevents, &event->zerocrossing));
1909566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nevents, &event->side));
1919566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nevents, &event->direction));
1929566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nevents, &event->terminate));
1939566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nevents, &event->vtol));
194d94325d3SShri Abhyankar   for (i = 0; i < nevents; i++) {
195d94325d3SShri Abhyankar     event->direction[i]    = direction[i];
196d94325d3SShri Abhyankar     event->terminate[i]    = terminate[i];
197e2cdd850SShri Abhyankar     event->zerocrossing[i] = PETSC_FALSE;
198e2cdd850SShri Abhyankar     event->side[i]         = 0;
199d94325d3SShri Abhyankar   }
2009566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nevents, &event->events_zero));
2012589fa24SLisandro Dalcin   event->nevents                    = nevents;
202*9b3d3759SBarry Smith   event->indicator                  = indicator;
2032dc7a7e3SShri Abhyankar   event->postevent                  = postevent;
2046427ac75SLisandro Dalcin   event->ctx                        = ctx;
205458122a4SShri Abhyankar   event->timestep_posteventinterval = ts->time_step;
2069566063dSJacob Faibussowitsch   PetscCall(TSGetAdapt(ts, &adapt));
2079566063dSJacob Faibussowitsch   PetscCall(TSAdaptGetStepLimits(adapt, &hmin, NULL));
208d294eb03SHong Zhang   event->timestep_min = hmin;
2092dc7a7e3SShri Abhyankar 
21002749585SLisandro Dalcin   event->recsize = 8; /* Initial size of the recorder */
211d0609cedSBarry Smith   PetscOptionsBegin(((PetscObject)ts)->comm, ((PetscObject)ts)->prefix, "TS Event options", "TS");
2122dc7a7e3SShri Abhyankar   {
2139566063dSJacob Faibussowitsch     PetscCall(PetscOptionsReal("-ts_event_tol", "Scalar event tolerance for zero crossing check", "TSSetEventTolerances", tol, &tol, NULL));
2149566063dSJacob Faibussowitsch     PetscCall(PetscOptionsName("-ts_event_monitor", "Print choices made by event handler", "", &flg));
2159566063dSJacob Faibussowitsch     PetscCall(PetscOptionsInt("-ts_event_recorder_initial_size", "Initial size of event recorder", "", event->recsize, &event->recsize, NULL));
2169566063dSJacob Faibussowitsch     PetscCall(PetscOptionsReal("-ts_event_post_eventinterval_step", "Time step after event interval", "", event->timestep_posteventinterval, &event->timestep_posteventinterval, NULL));
2179566063dSJacob Faibussowitsch     PetscCall(PetscOptionsReal("-ts_event_post_event_step", "Time step after event", "", event->timestep_postevent, &event->timestep_postevent, NULL));
2189566063dSJacob Faibussowitsch     PetscCall(PetscOptionsReal("-ts_event_dt_min", "Minimum time step considered for TSEvent", "", event->timestep_min, &event->timestep_min, NULL));
2192dc7a7e3SShri Abhyankar   }
220d0609cedSBarry Smith   PetscOptionsEnd();
221a4ffd976SShri Abhyankar 
2229566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(event->recsize, &event->recorder.time));
2239566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(event->recsize, &event->recorder.stepnum));
2249566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(event->recsize, &event->recorder.nevents));
2259566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(event->recsize, &event->recorder.eventidx));
22648a46eb9SPierre Jolivet   for (i = 0; i < event->recsize; i++) PetscCall(PetscMalloc1(event->nevents, &event->recorder.eventidx[i]));
227e7069c78SShri   /* Initialize the event recorder */
228e7069c78SShri   event->recorder.ctr = 0;
229a4ffd976SShri Abhyankar 
230e3005195SShri Abhyankar   for (i = 0; i < event->nevents; i++) event->vtol[i] = tol;
2319566063dSJacob Faibussowitsch   if (flg) PetscCall(PetscViewerASCIIOpen(PETSC_COMM_SELF, "stdout", &event->monitor));
2329e12be75SShri Abhyankar 
2339566063dSJacob Faibussowitsch   PetscCall(TSEventDestroy(&ts->event));
234d94325d3SShri Abhyankar   ts->event        = event;
235e7069c78SShri   ts->event->refct = 1;
2363ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2372dc7a7e3SShri Abhyankar }
2382dc7a7e3SShri Abhyankar 
239a4ffd976SShri Abhyankar /*
240a4ffd976SShri Abhyankar   TSEventRecorderResize - Resizes (2X) the event recorder arrays whenever the recording limit (event->recsize)
241a4ffd976SShri Abhyankar                           is reached.
242a4ffd976SShri Abhyankar */
243d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSEventRecorderResize(TSEvent event)
244d71ae5a4SJacob Faibussowitsch {
245a4ffd976SShri Abhyankar   PetscReal *time;
246a4ffd976SShri Abhyankar   PetscInt  *stepnum;
247a4ffd976SShri Abhyankar   PetscInt  *nevents;
248a4ffd976SShri Abhyankar   PetscInt **eventidx;
249a4ffd976SShri Abhyankar   PetscInt   i, fact = 2;
250a4ffd976SShri Abhyankar 
251a4ffd976SShri Abhyankar   PetscFunctionBegin;
252a4ffd976SShri Abhyankar 
253a4ffd976SShri Abhyankar   /* Create large arrays */
2549566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(fact * event->recsize, &time));
2559566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(fact * event->recsize, &stepnum));
2569566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(fact * event->recsize, &nevents));
2579566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(fact * event->recsize, &eventidx));
25848a46eb9SPierre Jolivet   for (i = 0; i < fact * event->recsize; i++) PetscCall(PetscMalloc1(event->nevents, &eventidx[i]));
259a4ffd976SShri Abhyankar 
260a4ffd976SShri Abhyankar   /* Copy over data */
2619566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(time, event->recorder.time, event->recsize));
2629566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(stepnum, event->recorder.stepnum, event->recsize));
2639566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(nevents, event->recorder.nevents, event->recsize));
26448a46eb9SPierre Jolivet   for (i = 0; i < event->recsize; i++) PetscCall(PetscArraycpy(eventidx[i], event->recorder.eventidx[i], event->recorder.nevents[i]));
265a4ffd976SShri Abhyankar 
266a4ffd976SShri Abhyankar   /* Destroy old arrays */
26748a46eb9SPierre Jolivet   for (i = 0; i < event->recsize; i++) PetscCall(PetscFree(event->recorder.eventidx[i]));
2689566063dSJacob Faibussowitsch   PetscCall(PetscFree(event->recorder.eventidx));
2699566063dSJacob Faibussowitsch   PetscCall(PetscFree(event->recorder.nevents));
2709566063dSJacob Faibussowitsch   PetscCall(PetscFree(event->recorder.stepnum));
2719566063dSJacob Faibussowitsch   PetscCall(PetscFree(event->recorder.time));
272a4ffd976SShri Abhyankar 
273a4ffd976SShri Abhyankar   /* Set pointers */
274a4ffd976SShri Abhyankar   event->recorder.time     = time;
275a4ffd976SShri Abhyankar   event->recorder.stepnum  = stepnum;
276a4ffd976SShri Abhyankar   event->recorder.nevents  = nevents;
277a4ffd976SShri Abhyankar   event->recorder.eventidx = eventidx;
278a4ffd976SShri Abhyankar 
279a4ffd976SShri Abhyankar   /* Double size */
280a4ffd976SShri Abhyankar   event->recsize *= fact;
281a4ffd976SShri Abhyankar 
2823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
283a4ffd976SShri Abhyankar }
284a4ffd976SShri Abhyankar 
285031fbad4SShri Abhyankar /*
286*9b3d3759SBarry Smith    Helper routine to handle user post-events and recording
287031fbad4SShri Abhyankar */
288d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSPostEvent(TS ts, PetscReal t, Vec U)
289d71ae5a4SJacob Faibussowitsch {
2902dc7a7e3SShri Abhyankar   TSEvent   event     = ts->event;
2912dc7a7e3SShri Abhyankar   PetscBool terminate = PETSC_FALSE;
29228d5b5d6SLisandro Dalcin   PetscBool restart   = PETSC_FALSE;
293d0578d90SShri Abhyankar   PetscInt  i, ctr, stepnum;
2947324a0ffSLisandro Dalcin   PetscBool inflag[2], outflag[2];
2954597913aSLisandro Dalcin   PetscBool forwardsolve = PETSC_TRUE; /* Flag indicating that TS is doing a forward solve */
2962dc7a7e3SShri Abhyankar 
2972dc7a7e3SShri Abhyankar   PetscFunctionBegin;
2982dc7a7e3SShri Abhyankar   if (event->postevent) {
29928d5b5d6SLisandro Dalcin     PetscObjectState state_prev, state_post;
3009566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateGet((PetscObject)U, &state_prev));
301*9b3d3759SBarry Smith     PetscCallBack("Event post-event processing", (*event->postevent)(ts, event->nevents_zero, event->events_zero, t, U, forwardsolve, event->ctx));
3029566063dSJacob Faibussowitsch     PetscCall(PetscObjectStateGet((PetscObject)U, &state_post));
30328d5b5d6SLisandro Dalcin     if (state_prev != state_post) restart = PETSC_TRUE;
3042dc7a7e3SShri Abhyankar   }
3054597913aSLisandro Dalcin 
30628d5b5d6SLisandro Dalcin   /* Handle termination events and step restart */
3079371c9d4SSatish Balay   for (i = 0; i < event->nevents_zero; i++)
3089371c9d4SSatish Balay     if (event->terminate[event->events_zero[i]]) terminate = PETSC_TRUE;
3099371c9d4SSatish Balay   inflag[0] = restart;
3109371c9d4SSatish Balay   inflag[1] = terminate;
3111c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(inflag, outflag, 2, MPIU_BOOL, MPI_LOR, ((PetscObject)ts)->comm));
3129371c9d4SSatish Balay   restart   = outflag[0];
3139371c9d4SSatish Balay   terminate = outflag[1];
3149566063dSJacob Faibussowitsch   if (restart) PetscCall(TSRestartStep(ts));
3159566063dSJacob Faibussowitsch   if (terminate) PetscCall(TSSetConvergedReason(ts, TS_CONVERGED_EVENT));
3167324a0ffSLisandro Dalcin   event->status = terminate ? TSEVENT_NONE : TSEVENT_RESET_NEXTSTEP;
317f7aea88cSShri Abhyankar 
318*9b3d3759SBarry Smith   /* Reset event indicator function values as states might get changed by the post-event callback */
319f443add6SLisandro Dalcin   if (event->postevent) {
3209566063dSJacob Faibussowitsch     PetscCall(VecLockReadPush(U));
321*9b3d3759SBarry Smith     PetscCallBack("Event indicator", (*event->indicator)(ts, t, U, event->fvalue, event->ctx));
3229566063dSJacob Faibussowitsch     PetscCall(VecLockReadPop(U));
323f443add6SLisandro Dalcin   }
324f443add6SLisandro Dalcin 
325f443add6SLisandro Dalcin   /* Cache current time and event residual functions */
326f443add6SLisandro Dalcin   event->ptime_prev = t;
3279371c9d4SSatish Balay   for (i = 0; i < event->nevents; i++) event->fvalue_prev[i] = event->fvalue[i];
3284597913aSLisandro Dalcin 
329d0578d90SShri Abhyankar   /* Record the event in the event recorder */
3309566063dSJacob Faibussowitsch   PetscCall(TSGetStepNumber(ts, &stepnum));
331f7aea88cSShri Abhyankar   ctr = event->recorder.ctr;
33248a46eb9SPierre Jolivet   if (ctr == event->recsize) PetscCall(TSEventRecorderResize(event));
333f7aea88cSShri Abhyankar   event->recorder.time[ctr]    = t;
334d0578d90SShri Abhyankar   event->recorder.stepnum[ctr] = stepnum;
3354597913aSLisandro Dalcin   event->recorder.nevents[ctr] = event->nevents_zero;
3364597913aSLisandro Dalcin   for (i = 0; i < event->nevents_zero; i++) event->recorder.eventidx[ctr][i] = event->events_zero[i];
337f7aea88cSShri Abhyankar   event->recorder.ctr++;
3383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3392dc7a7e3SShri Abhyankar }
3402dc7a7e3SShri Abhyankar 
34102749585SLisandro Dalcin /* Uses Anderson-Bjorck variant of regula falsi method */
342d71ae5a4SJacob Faibussowitsch static inline PetscReal TSEventComputeStepSize(PetscReal tleft, PetscReal t, PetscReal tright, PetscScalar fleft, PetscScalar f, PetscScalar fright, PetscInt side, PetscReal dt)
343d71ae5a4SJacob Faibussowitsch {
34402749585SLisandro Dalcin   PetscReal new_dt, scal = 1.0;
345e2cdd850SShri Abhyankar   if (PetscRealPart(fleft) * PetscRealPart(f) < 0) {
346e2cdd850SShri Abhyankar     if (side == 1) {
347a6c783d2SShri Abhyankar       scal = (PetscRealPart(fright) - PetscRealPart(f)) / PetscRealPart(fright);
348a6c783d2SShri Abhyankar       if (scal < PETSC_SMALL) scal = 0.5;
349e2cdd850SShri Abhyankar     }
35002749585SLisandro Dalcin     new_dt = (scal * PetscRealPart(fleft) * t - PetscRealPart(f) * tleft) / (scal * PetscRealPart(fleft) - PetscRealPart(f)) - tleft;
351e2cdd850SShri Abhyankar   } else {
352e2cdd850SShri Abhyankar     if (side == -1) {
353a6c783d2SShri Abhyankar       scal = (PetscRealPart(fleft) - PetscRealPart(f)) / PetscRealPart(fleft);
354a6c783d2SShri Abhyankar       if (scal < PETSC_SMALL) scal = 0.5;
355e2cdd850SShri Abhyankar     }
35602749585SLisandro Dalcin     new_dt = (PetscRealPart(f) * tright - scal * PetscRealPart(fright) * t) / (PetscRealPart(f) - scal * PetscRealPart(fright)) - t;
357e2cdd850SShri Abhyankar   }
35802749585SLisandro Dalcin   return PetscMin(dt, new_dt);
35938bf2713SShri Abhyankar }
360e2cdd850SShri Abhyankar 
361d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSEventDetection(TS ts)
362d71ae5a4SJacob Faibussowitsch {
363d294eb03SHong Zhang   TSEvent   event = ts->event;
364d294eb03SHong Zhang   PetscReal t;
365d294eb03SHong Zhang   PetscInt  i;
366d294eb03SHong Zhang   PetscInt  fvalue_sign, fvalueprev_sign;
367ea3dac1cSHong Zhang   PetscInt  in, out;
368d294eb03SHong Zhang 
369d294eb03SHong Zhang   PetscFunctionBegin;
3709566063dSJacob Faibussowitsch   PetscCall(TSGetTime(ts, &t));
371d294eb03SHong Zhang   for (i = 0; i < event->nevents; i++) {
372d294eb03SHong Zhang     if (PetscAbsScalar(event->fvalue[i]) < event->vtol[i]) {
373d294eb03SHong Zhang       if (!event->iterctr) event->zerocrossing[i] = PETSC_TRUE;
374d294eb03SHong Zhang       event->status = TSEVENT_LOCATED_INTERVAL;
375d294eb03SHong Zhang       if (event->monitor) {
37663a3b9bcSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(event->monitor, "TSEvent: iter %" PetscInt_FMT " - Event %" PetscInt_FMT " interval detected due to zero value (tol=%g) [%g - %g]\n", event->iterctr, i, (double)event->vtol[i], (double)event->ptime_prev, (double)t));
377d294eb03SHong Zhang       }
378d294eb03SHong Zhang       continue;
379d294eb03SHong Zhang     }
380ea3dac1cSHong Zhang     if (PetscAbsScalar(event->fvalue_prev[i]) < event->vtol[i]) continue; /* avoid duplicative detection if the previous endpoint is an event location */
381d294eb03SHong Zhang     fvalue_sign     = PetscSign(PetscRealPart(event->fvalue[i]));
382d294eb03SHong Zhang     fvalueprev_sign = PetscSign(PetscRealPart(event->fvalue_prev[i]));
383d294eb03SHong Zhang     if (fvalueprev_sign != 0 && (fvalue_sign != fvalueprev_sign)) {
384d294eb03SHong Zhang       if (!event->iterctr) event->zerocrossing[i] = PETSC_TRUE;
385d294eb03SHong Zhang       event->status = TSEVENT_LOCATED_INTERVAL;
38648a46eb9SPierre Jolivet       if (event->monitor) PetscCall(PetscViewerASCIIPrintf(event->monitor, "TSEvent: iter %" PetscInt_FMT " - Event %" PetscInt_FMT " interval detected due to sign change [%g - %g]\n", event->iterctr, i, (double)event->ptime_prev, (double)t));
387d294eb03SHong Zhang     }
388d294eb03SHong Zhang   }
389d5f990dbSBarry Smith   in = (PetscInt)event->status;
3901c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&in, &out, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)ts)));
391ea3dac1cSHong Zhang   event->status = (TSEventStatus)out;
3923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
393d294eb03SHong Zhang }
394d294eb03SHong Zhang 
395d71ae5a4SJacob Faibussowitsch static PetscErrorCode TSEventLocation(TS ts, PetscReal *dt)
396d71ae5a4SJacob Faibussowitsch {
397d294eb03SHong Zhang   TSEvent   event = ts->event;
39844ceb375SMatthew G. Knepley   PetscReal diff  = PetscAbsReal((event->ptime_right - event->ptime_prev) / 2);
399d294eb03SHong Zhang   PetscInt  i;
400d294eb03SHong Zhang   PetscReal t;
401ea3dac1cSHong Zhang   PetscInt  fvalue_sign, fvalueprev_sign;
402ea3dac1cSHong Zhang   PetscInt  rollback = 0, in[2], out[2];
403d294eb03SHong Zhang 
404d294eb03SHong Zhang   PetscFunctionBegin;
4059566063dSJacob Faibussowitsch   PetscCall(TSGetTime(ts, &t));
406d294eb03SHong Zhang   event->nevents_zero = 0;
407d294eb03SHong Zhang   for (i = 0; i < event->nevents; i++) {
408d294eb03SHong Zhang     if (event->zerocrossing[i]) {
40944ceb375SMatthew G. Knepley       if (PetscAbsScalar(event->fvalue[i]) < event->vtol[i] || *dt < event->timestep_min || PetscAbsReal(*dt) < diff * event->vtol[i]) { /* stopping criteria */
410d294eb03SHong Zhang         event->status          = TSEVENT_ZERO;
411d294eb03SHong Zhang         event->fvalue_right[i] = event->fvalue[i];
412d294eb03SHong Zhang         continue;
413d294eb03SHong Zhang       }
414d294eb03SHong Zhang       /* Compute new time step */
415d294eb03SHong Zhang       *dt             = TSEventComputeStepSize(event->ptime_prev, t, event->ptime_right, event->fvalue_prev[i], event->fvalue[i], event->fvalue_right[i], event->side[i], *dt);
416d294eb03SHong Zhang       fvalue_sign     = PetscSign(PetscRealPart(event->fvalue[i]));
417ea3dac1cSHong Zhang       fvalueprev_sign = PetscSign(PetscRealPart(event->fvalue_prev[i]));
418d294eb03SHong Zhang       switch (event->direction[i]) {
419d294eb03SHong Zhang       case -1:
420d294eb03SHong Zhang         if (fvalue_sign < 0) {
421ea3dac1cSHong Zhang           rollback               = 1;
422d294eb03SHong Zhang           event->fvalue_right[i] = event->fvalue[i];
423d294eb03SHong Zhang           event->side[i]         = 1;
424d294eb03SHong Zhang         }
425d294eb03SHong Zhang         break;
426d294eb03SHong Zhang       case 1:
427d294eb03SHong Zhang         if (fvalue_sign > 0) {
428ea3dac1cSHong Zhang           rollback               = 1;
429d294eb03SHong Zhang           event->fvalue_right[i] = event->fvalue[i];
430d294eb03SHong Zhang           event->side[i]         = 1;
431d294eb03SHong Zhang         }
432d294eb03SHong Zhang         break;
433d294eb03SHong Zhang       case 0:
434ea3dac1cSHong Zhang         if (fvalue_sign != fvalueprev_sign) { /* trigger rollback only when there is a sign change */
435ea3dac1cSHong Zhang           rollback               = 1;
436d294eb03SHong Zhang           event->fvalue_right[i] = event->fvalue[i];
437d294eb03SHong Zhang           event->side[i]         = 1;
438ea3dac1cSHong Zhang         }
439d294eb03SHong Zhang         break;
440d294eb03SHong Zhang       }
441ea3dac1cSHong Zhang       if (event->status == TSEVENT_PROCESSING) event->side[i] = -1;
442d294eb03SHong Zhang     }
443d294eb03SHong Zhang   }
4449371c9d4SSatish Balay   in[0] = (PetscInt)event->status;
4459371c9d4SSatish Balay   in[1] = rollback;
4461c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(in, out, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)ts)));
4479371c9d4SSatish Balay   event->status = (TSEventStatus)out[0];
4489371c9d4SSatish Balay   rollback      = out[1];
449da81f932SPierre Jolivet   /* If rollback is true, the status will be overwritten so that an event at the endtime of current time step will be postponed to guarantee correct order */
450ea3dac1cSHong Zhang   if (rollback) event->status = TSEVENT_LOCATED_INTERVAL;
451d294eb03SHong Zhang   if (event->status == TSEVENT_ZERO) {
452ea3dac1cSHong Zhang     for (i = 0; i < event->nevents; i++) {
453ea3dac1cSHong Zhang       if (event->zerocrossing[i]) {
45444ceb375SMatthew G. Knepley         if (PetscAbsScalar(event->fvalue[i]) < event->vtol[i] || *dt < event->timestep_min || PetscAbsReal(*dt) < diff * event->vtol[i]) { /* stopping criteria */
455ea3dac1cSHong Zhang           event->events_zero[event->nevents_zero++] = i;
45648a46eb9SPierre Jolivet           if (event->monitor) PetscCall(PetscViewerASCIIPrintf(event->monitor, "TSEvent: iter %" PetscInt_FMT " - Event %" PetscInt_FMT " zero crossing located at time %g\n", event->iterctr, i, (double)t));
457ea3dac1cSHong Zhang           event->zerocrossing[i] = PETSC_FALSE;
458ea3dac1cSHong Zhang         }
459ea3dac1cSHong Zhang       }
460ea3dac1cSHong Zhang       event->side[i] = 0;
461ea3dac1cSHong Zhang     }
462d294eb03SHong Zhang   }
4633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
464d294eb03SHong Zhang }
46538bf2713SShri Abhyankar 
466d71ae5a4SJacob Faibussowitsch PetscErrorCode TSEventHandler(TS ts)
467d71ae5a4SJacob Faibussowitsch {
4686427ac75SLisandro Dalcin   TSEvent   event;
4692dc7a7e3SShri Abhyankar   PetscReal t;
4702dc7a7e3SShri Abhyankar   Vec       U;
4712dc7a7e3SShri Abhyankar   PetscInt  i;
472ea3dac1cSHong Zhang   PetscReal dt, dt_min, dt_reset = 0.0;
4732dc7a7e3SShri Abhyankar 
4742dc7a7e3SShri Abhyankar   PetscFunctionBegin;
4756427ac75SLisandro Dalcin   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
4763ba16761SJacob Faibussowitsch   if (!ts->event) PetscFunctionReturn(PETSC_SUCCESS);
4776427ac75SLisandro Dalcin   event = ts->event;
4782dc7a7e3SShri Abhyankar 
4799566063dSJacob Faibussowitsch   PetscCall(TSGetTime(ts, &t));
4809566063dSJacob Faibussowitsch   PetscCall(TSGetTimeStep(ts, &dt));
4819566063dSJacob Faibussowitsch   PetscCall(TSGetSolution(ts, &U));
4822dc7a7e3SShri Abhyankar 
4837dbe0728SLisandro Dalcin   if (event->status == TSEVENT_NONE) {
4847dbe0728SLisandro Dalcin     event->timestep_prev = dt;
485d294eb03SHong Zhang     event->ptime_end     = t;
4867dbe0728SLisandro Dalcin   }
4872dc7a7e3SShri Abhyankar   if (event->status == TSEVENT_RESET_NEXTSTEP) {
488d294eb03SHong Zhang     /* user has specified a PostEventInterval dt */
489458122a4SShri Abhyankar     dt = event->timestep_posteventinterval;
490e97c63d7SStefano Zampini     if (ts->exact_final_time == TS_EXACTFINALTIME_MATCHSTEP) {
491e97c63d7SStefano Zampini       PetscReal maxdt = ts->max_time - t;
492e97c63d7SStefano Zampini       dt              = dt > maxdt ? maxdt : (PetscIsCloseAtTol(dt, maxdt, 10 * PETSC_MACHINE_EPSILON, 0) ? maxdt : dt);
493e97c63d7SStefano Zampini     }
4949566063dSJacob Faibussowitsch     PetscCall(TSSetTimeStep(ts, dt));
4952dc7a7e3SShri Abhyankar     event->status = TSEVENT_NONE;
4962dc7a7e3SShri Abhyankar   }
4972dc7a7e3SShri Abhyankar 
4989566063dSJacob Faibussowitsch   PetscCall(VecLockReadPush(U));
499*9b3d3759SBarry Smith   PetscCallBack("Event indicator", (*event->indicator)(ts, t, U, event->fvalue, event->ctx));
5009566063dSJacob Faibussowitsch   PetscCall(VecLockReadPop(U));
5019e12be75SShri Abhyankar 
502d294eb03SHong Zhang   /* Detect the events */
5039566063dSJacob Faibussowitsch   PetscCall(TSEventDetection(ts));
504d294eb03SHong Zhang 
505d294eb03SHong Zhang   /* Locate the events */
506d294eb03SHong Zhang   if (event->status == TSEVENT_LOCATED_INTERVAL || event->status == TSEVENT_PROCESSING) {
507d294eb03SHong Zhang     /* Approach the zero crosing by setting a new step size */
5089566063dSJacob Faibussowitsch     PetscCall(TSEventLocation(ts, &dt));
509d294eb03SHong Zhang     /* Roll back when new events are detected */
510d294eb03SHong Zhang     if (event->status == TSEVENT_LOCATED_INTERVAL) {
5119566063dSJacob Faibussowitsch       PetscCall(TSRollBack(ts));
5129566063dSJacob Faibussowitsch       PetscCall(TSSetConvergedReason(ts, TS_CONVERGED_ITERATING));
513d294eb03SHong Zhang       event->iterctr++;
514006e6a18SShri Abhyankar     }
5151c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&dt, &dt_min, 1, MPIU_REAL, MPIU_MIN, PetscObjectComm((PetscObject)ts)));
516ea3dac1cSHong Zhang     if (dt_reset > 0.0 && dt_reset < dt_min) dt_min = dt_reset;
5179566063dSJacob Faibussowitsch     PetscCall(TSSetTimeStep(ts, dt_min));
518d294eb03SHong Zhang     /* Found the zero crossing */
5199e12be75SShri Abhyankar     if (event->status == TSEVENT_ZERO) {
5209566063dSJacob Faibussowitsch       PetscCall(TSPostEvent(ts, t, U));
521e2cdd850SShri Abhyankar       dt = event->ptime_end - t;
522ad508104SStefano Zampini       if (PetscAbsReal(dt) < PETSC_SMALL) { /* we hit the event, continue with the candidate time step */
523ad508104SStefano Zampini         dt            = event->timestep_prev;
524ad508104SStefano Zampini         event->status = TSEVENT_NONE;
525ad508104SStefano Zampini       }
526d294eb03SHong Zhang       if (event->timestep_postevent) { /* user has specified a PostEvent dt*/
527d294eb03SHong Zhang         dt = event->timestep_postevent;
528d294eb03SHong Zhang       }
529e97c63d7SStefano Zampini       if (ts->exact_final_time == TS_EXACTFINALTIME_MATCHSTEP) {
530e97c63d7SStefano Zampini         PetscReal maxdt = ts->max_time - t;
531e97c63d7SStefano Zampini         dt              = dt > maxdt ? maxdt : (PetscIsCloseAtTol(dt, maxdt, 10 * PETSC_MACHINE_EPSILON, 0) ? maxdt : dt);
532e97c63d7SStefano Zampini       }
5339566063dSJacob Faibussowitsch       PetscCall(TSSetTimeStep(ts, dt));
53438bf2713SShri Abhyankar       event->iterctr = 0;
5359e12be75SShri Abhyankar     }
536d294eb03SHong Zhang     /* Have not found the zero crosing yet */
537d294eb03SHong Zhang     if (event->status == TSEVENT_PROCESSING) {
53848a46eb9SPierre Jolivet       if (event->monitor) PetscCall(PetscViewerASCIIPrintf(event->monitor, "TSEvent: iter %" PetscInt_FMT " - Stepping forward as no event detected in interval [%g - %g]\n", event->iterctr, (double)event->ptime_prev, (double)t));
539d294eb03SHong Zhang       event->iterctr++;
540d294eb03SHong Zhang     }
541d294eb03SHong Zhang   }
542d294eb03SHong Zhang   if (event->status == TSEVENT_LOCATED_INTERVAL) { /* The step has been rolled back */
5432dc7a7e3SShri Abhyankar     event->status      = TSEVENT_PROCESSING;
544e2cdd850SShri Abhyankar     event->ptime_right = t;
5452dc7a7e3SShri Abhyankar   } else {
546d294eb03SHong Zhang     for (i = 0; i < event->nevents; i++) event->fvalue_prev[i] = event->fvalue[i];
54738bf2713SShri Abhyankar     event->ptime_prev = t;
54838bf2713SShri Abhyankar   }
5493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5502dc7a7e3SShri Abhyankar }
5512dc7a7e3SShri Abhyankar 
552d71ae5a4SJacob Faibussowitsch PetscErrorCode TSAdjointEventHandler(TS ts)
553d71ae5a4SJacob Faibussowitsch {
5546427ac75SLisandro Dalcin   TSEvent   event;
555d0578d90SShri Abhyankar   PetscReal t;
556d0578d90SShri Abhyankar   Vec       U;
557d0578d90SShri Abhyankar   PetscInt  ctr;
558d0578d90SShri Abhyankar   PetscBool forwardsolve = PETSC_FALSE; /* Flag indicating that TS is doing an adjoint solve */
559d0578d90SShri Abhyankar 
560d0578d90SShri Abhyankar   PetscFunctionBegin;
5616427ac75SLisandro Dalcin   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
5623ba16761SJacob Faibussowitsch   if (!ts->event) PetscFunctionReturn(PETSC_SUCCESS);
5636427ac75SLisandro Dalcin   event = ts->event;
564d0578d90SShri Abhyankar 
5659566063dSJacob Faibussowitsch   PetscCall(TSGetTime(ts, &t));
5669566063dSJacob Faibussowitsch   PetscCall(TSGetSolution(ts, &U));
567d0578d90SShri Abhyankar 
568d0578d90SShri Abhyankar   ctr = event->recorder.ctr - 1;
569bcbf8bb3SShri Abhyankar   if (ctr >= 0 && PetscAbsReal(t - event->recorder.time[ctr]) < PETSC_SMALL) {
570*9b3d3759SBarry Smith     /* Call the user post-event function */
571d0578d90SShri Abhyankar     if (event->postevent) {
572*9b3d3759SBarry Smith       PetscCallBack("Event post-event processing", (*event->postevent)(ts, event->recorder.nevents[ctr], event->recorder.eventidx[ctr], t, U, forwardsolve, event->ctx));
573d0578d90SShri Abhyankar       event->recorder.ctr--;
574d0578d90SShri Abhyankar     }
575d0578d90SShri Abhyankar   }
5763ba16761SJacob Faibussowitsch   PetscCall(PetscBarrier((PetscObject)ts));
5773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
578d0578d90SShri Abhyankar }
5791ea83e56SMiguel 
5801ea83e56SMiguel /*@
58120f4b53cSBarry Smith   TSGetNumEvents - Get the numbers of events currently set to be detected
5821ea83e56SMiguel 
5831ea83e56SMiguel   Logically Collective
5841ea83e56SMiguel 
5854165533cSJose E. Roman   Input Parameter:
586bcf0153eSBarry Smith . ts - the `TS` context
5871ea83e56SMiguel 
5884165533cSJose E. Roman   Output Parameter:
58920f4b53cSBarry Smith . nevents - the number of events
5901ea83e56SMiguel 
5911ea83e56SMiguel   Level: intermediate
5921ea83e56SMiguel 
5931cc06b55SBarry Smith .seealso: [](ch_ts), `TSEvent`, `TSSetEventHandler()`
5941ea83e56SMiguel @*/
595d71ae5a4SJacob Faibussowitsch PetscErrorCode TSGetNumEvents(TS ts, PetscInt *nevents)
596d71ae5a4SJacob Faibussowitsch {
5971ea83e56SMiguel   PetscFunctionBegin;
5981ea83e56SMiguel   *nevents = ts->event->nevents;
5993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6001ea83e56SMiguel }
601