xref: /petsc/src/ts/event/tsevent.c (revision 4dfa11a44d5adf2389f1d3acbc8f3c1116dc6c3a)
1af0996ceSBarry Smith #include <petsc/private/tsimpl.h> /*I  "petscts.h" I*/
22dc7a7e3SShri Abhyankar 
36fea3669SShri Abhyankar /*
46427ac75SLisandro Dalcin   TSEventInitialize - Initializes TSEvent for TSSolve
56fea3669SShri Abhyankar */
69371c9d4SSatish Balay PetscErrorCode TSEventInitialize(TSEvent event, TS ts, PetscReal t, Vec U) {
76fea3669SShri Abhyankar   PetscFunctionBegin;
86427ac75SLisandro Dalcin   if (!event) PetscFunctionReturn(0);
96427ac75SLisandro Dalcin   PetscValidPointer(event, 1);
106427ac75SLisandro Dalcin   PetscValidHeaderSpecific(ts, TS_CLASSID, 2);
116427ac75SLisandro Dalcin   PetscValidHeaderSpecific(U, VEC_CLASSID, 4);
126fea3669SShri Abhyankar   event->ptime_prev = t;
1338bf2713SShri Abhyankar   event->iterctr    = 0;
149566063dSJacob Faibussowitsch   PetscCall((*event->eventhandler)(ts, t, U, event->fvalue_prev, event->ctx));
156fea3669SShri Abhyankar   PetscFunctionReturn(0);
166fea3669SShri Abhyankar }
176fea3669SShri Abhyankar 
189371c9d4SSatish Balay PetscErrorCode TSEventDestroy(TSEvent *event) {
197dbe0728SLisandro Dalcin   PetscInt i;
207dbe0728SLisandro Dalcin 
217dbe0728SLisandro Dalcin   PetscFunctionBegin;
227dbe0728SLisandro Dalcin   PetscValidPointer(event, 1);
237dbe0728SLisandro Dalcin   if (!*event) PetscFunctionReturn(0);
249371c9d4SSatish Balay   if (--(*event)->refct > 0) {
259371c9d4SSatish Balay     *event = NULL;
269371c9d4SSatish Balay     PetscFunctionReturn(0);
279371c9d4SSatish Balay   }
28e7069c78SShri 
299566063dSJacob Faibussowitsch   PetscCall(PetscFree((*event)->fvalue));
309566063dSJacob Faibussowitsch   PetscCall(PetscFree((*event)->fvalue_prev));
319566063dSJacob Faibussowitsch   PetscCall(PetscFree((*event)->fvalue_right));
329566063dSJacob Faibussowitsch   PetscCall(PetscFree((*event)->zerocrossing));
339566063dSJacob Faibussowitsch   PetscCall(PetscFree((*event)->side));
349566063dSJacob Faibussowitsch   PetscCall(PetscFree((*event)->direction));
359566063dSJacob Faibussowitsch   PetscCall(PetscFree((*event)->terminate));
369566063dSJacob Faibussowitsch   PetscCall(PetscFree((*event)->events_zero));
379566063dSJacob Faibussowitsch   PetscCall(PetscFree((*event)->vtol));
38a4ffd976SShri Abhyankar 
3948a46eb9SPierre Jolivet   for (i = 0; i < (*event)->recsize; i++) PetscCall(PetscFree((*event)->recorder.eventidx[i]));
409566063dSJacob Faibussowitsch   PetscCall(PetscFree((*event)->recorder.eventidx));
419566063dSJacob Faibussowitsch   PetscCall(PetscFree((*event)->recorder.nevents));
429566063dSJacob Faibussowitsch   PetscCall(PetscFree((*event)->recorder.stepnum));
439566063dSJacob Faibussowitsch   PetscCall(PetscFree((*event)->recorder.time));
44a4ffd976SShri Abhyankar 
459566063dSJacob Faibussowitsch   PetscCall(PetscViewerDestroy(&(*event)->monitor));
469566063dSJacob Faibussowitsch   PetscCall(PetscFree(*event));
477dbe0728SLisandro Dalcin   PetscFunctionReturn(0);
487dbe0728SLisandro Dalcin }
497dbe0728SLisandro Dalcin 
50e3005195SShri Abhyankar /*@
51ac6a796dSBarry Smith   TSSetPostEventIntervalStep - Set the time-step used immediately following the event interval
52458122a4SShri Abhyankar 
53458122a4SShri Abhyankar   Logically Collective
54458122a4SShri Abhyankar 
554165533cSJose E. Roman   Input Parameters:
56458122a4SShri Abhyankar + ts - time integration context
57458122a4SShri Abhyankar - dt - post event interval step
58458122a4SShri Abhyankar 
59458122a4SShri Abhyankar   Options Database Keys:
60458122a4SShri Abhyankar . -ts_event_post_eventinterval_step <dt> time-step after event interval
61458122a4SShri Abhyankar 
62458122a4SShri Abhyankar   Notes:
63ac6a796dSBarry Smith   TSSetPostEventIntervalStep allows one to set a time-step that is used immediately following an event interval.
64458122a4SShri Abhyankar 
65458122a4SShri Abhyankar   This function should be called from the postevent function set with TSSetEventHandler().
66458122a4SShri Abhyankar 
67458122a4SShri Abhyankar   The post event interval time-step should be selected based on the dynamics following the event.
68458122a4SShri Abhyankar   If the dynamics are stiff, a conservative (small) step should be used.
69458122a4SShri Abhyankar   If not, then a larger time-step can be used.
70458122a4SShri Abhyankar 
71458122a4SShri Abhyankar   Level: Advanced
72db781477SPatrick Sanan   .seealso: `TS`, `TSEvent`, `TSSetEventHandler()`
73458122a4SShri Abhyankar @*/
749371c9d4SSatish Balay PetscErrorCode TSSetPostEventIntervalStep(TS ts, PetscReal dt) {
75458122a4SShri Abhyankar   PetscFunctionBegin;
76458122a4SShri Abhyankar   ts->event->timestep_posteventinterval = dt;
77458122a4SShri Abhyankar   PetscFunctionReturn(0);
78458122a4SShri Abhyankar }
79458122a4SShri Abhyankar 
80458122a4SShri Abhyankar /*@
81e3005195SShri Abhyankar    TSSetEventTolerances - Set tolerances for event zero crossings when using event handler
82e3005195SShri Abhyankar 
83e3005195SShri Abhyankar    Logically Collective
84e3005195SShri Abhyankar 
854165533cSJose E. Roman    Input Parameters:
86e3005195SShri Abhyankar +  ts - time integration context
87e3005195SShri Abhyankar .  tol - scalar tolerance, PETSC_DECIDE to leave current value
88e3005195SShri Abhyankar -  vtol - array of tolerances or NULL, used in preference to tol if present
89e3005195SShri Abhyankar 
902589fa24SLisandro Dalcin    Options Database Keys:
91147403d9SBarry Smith .  -ts_event_tol <tol> - tolerance for event zero crossing
92e3005195SShri Abhyankar 
93e3005195SShri Abhyankar    Notes:
94f25fe674SLisandro Dalcin    Must call TSSetEventHandler() before setting the tolerances.
95e3005195SShri Abhyankar 
96e3005195SShri Abhyankar    The size of vtol is equal to the number of events.
97e3005195SShri Abhyankar 
98e3005195SShri Abhyankar    Level: beginner
99e3005195SShri Abhyankar 
100db781477SPatrick Sanan .seealso: `TS`, `TSEvent`, `TSSetEventHandler()`
101e3005195SShri Abhyankar @*/
1029371c9d4SSatish Balay PetscErrorCode TSSetEventTolerances(TS ts, PetscReal tol, PetscReal vtol[]) {
1036427ac75SLisandro Dalcin   TSEvent  event;
104e3005195SShri Abhyankar   PetscInt i;
105e3005195SShri Abhyankar 
106e3005195SShri Abhyankar   PetscFunctionBegin;
1076427ac75SLisandro Dalcin   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1086427ac75SLisandro Dalcin   if (vtol) PetscValidRealPointer(vtol, 3);
1093c633725SBarry Smith   PetscCheck(ts->event, PetscObjectComm((PetscObject)ts), PETSC_ERR_USER, "Must set the events first by calling TSSetEventHandler()");
1106427ac75SLisandro Dalcin 
1116427ac75SLisandro Dalcin   event = ts->event;
112e3005195SShri Abhyankar   if (vtol) {
113e3005195SShri Abhyankar     for (i = 0; i < event->nevents; i++) event->vtol[i] = vtol[i];
114e3005195SShri Abhyankar   } else {
115e3005195SShri Abhyankar     if (tol != PETSC_DECIDE || tol != PETSC_DEFAULT) {
116e3005195SShri Abhyankar       for (i = 0; i < event->nevents; i++) event->vtol[i] = tol;
117e3005195SShri Abhyankar     }
118e3005195SShri Abhyankar   }
119e3005195SShri Abhyankar   PetscFunctionReturn(0);
120e3005195SShri Abhyankar }
121e3005195SShri Abhyankar 
1222dc7a7e3SShri Abhyankar /*@C
123ac6a796dSBarry Smith    TSSetEventHandler - Sets a function used for detecting events
1242dc7a7e3SShri Abhyankar 
1252dc7a7e3SShri Abhyankar    Logically Collective on TS
1262dc7a7e3SShri Abhyankar 
1272dc7a7e3SShri Abhyankar    Input Parameters:
1282dc7a7e3SShri Abhyankar +  ts - the TS context obtained from TSCreate()
1292dc7a7e3SShri Abhyankar .  nevents - number of local events
130d94325d3SShri Abhyankar .  direction - direction of zero crossing to be detected. -1 => Zero crossing in negative direction,
131d94325d3SShri Abhyankar                +1 => Zero crossing in positive direction, 0 => both ways (one for each event)
132d94325d3SShri Abhyankar .  terminate - flag to indicate whether time stepping should be terminated after
133d94325d3SShri Abhyankar                event is detected (one for each event)
1346427ac75SLisandro Dalcin .  eventhandler - event monitoring routine
1352dc7a7e3SShri Abhyankar .  postevent - [optional] post-event function
1362589fa24SLisandro Dalcin -  ctx       - [optional] user-defined context for private data for the
1372dc7a7e3SShri Abhyankar                event monitor and post event routine (use NULL if no
1382dc7a7e3SShri Abhyankar                context is desired)
1392dc7a7e3SShri Abhyankar 
1406427ac75SLisandro Dalcin    Calling sequence of eventhandler:
1413a88037aSBarry Smith    PetscErrorCode PetscEventHandler(TS ts,PetscReal t,Vec U,PetscScalar fvalue[],void* ctx)
1422dc7a7e3SShri Abhyankar 
1432dc7a7e3SShri Abhyankar    Input Parameters:
1442dc7a7e3SShri Abhyankar +  ts  - the TS context
1452dc7a7e3SShri Abhyankar .  t   - current time
1462dc7a7e3SShri Abhyankar .  U   - current iterate
1476427ac75SLisandro Dalcin -  ctx - [optional] context passed with eventhandler
1482dc7a7e3SShri Abhyankar 
1492dc7a7e3SShri Abhyankar    Output parameters:
150d94325d3SShri Abhyankar .  fvalue    - function value of events at time t
1512dc7a7e3SShri Abhyankar 
1522dc7a7e3SShri Abhyankar    Calling sequence of postevent:
1532589fa24SLisandro Dalcin    PetscErrorCode PostEvent(TS ts,PetscInt nevents_zero,PetscInt events_zero[],PetscReal t,Vec U,PetscBool forwardsolve,void* ctx)
1542dc7a7e3SShri Abhyankar 
1552dc7a7e3SShri Abhyankar    Input Parameters:
1562dc7a7e3SShri Abhyankar +  ts - the TS context
1572dc7a7e3SShri Abhyankar .  nevents_zero - number of local events whose event function is zero
1582dc7a7e3SShri Abhyankar .  events_zero  - indices of local events which have reached zero
1592dc7a7e3SShri Abhyankar .  t            - current time
1602dc7a7e3SShri Abhyankar .  U            - current solution
161031fbad4SShri Abhyankar .  forwardsolve - Flag to indicate whether TS is doing a forward solve (1) or adjoint solve (0)
1626427ac75SLisandro Dalcin -  ctx          - the context passed with eventhandler
1632dc7a7e3SShri Abhyankar 
1642dc7a7e3SShri Abhyankar    Level: intermediate
1652dc7a7e3SShri Abhyankar 
166db781477SPatrick Sanan .seealso: `TSCreate()`, `TSSetTimeStep()`, `TSSetConvergedReason()`
1672dc7a7e3SShri Abhyankar @*/
1689371c9d4SSatish Balay PetscErrorCode TSSetEventHandler(TS ts, PetscInt nevents, PetscInt direction[], PetscBool terminate[], PetscErrorCode (*eventhandler)(TS, PetscReal, Vec, PetscScalar[], void *), PetscErrorCode (*postevent)(TS, PetscInt, PetscInt[], PetscReal, Vec, PetscBool, void *), void *ctx) {
169d294eb03SHong Zhang   TSAdapt   adapt;
170d294eb03SHong Zhang   PetscReal hmin;
1712dc7a7e3SShri Abhyankar   TSEvent   event;
172d94325d3SShri Abhyankar   PetscInt  i;
173006e6a18SShri Abhyankar   PetscBool flg;
174a6c783d2SShri Abhyankar #if defined PETSC_USE_REAL_SINGLE
175a6c783d2SShri Abhyankar   PetscReal tol = 1e-4;
176a6c783d2SShri Abhyankar #else
177d569cc17SSatish Balay   PetscReal tol = 1e-6;
178a6c783d2SShri Abhyankar #endif
1792dc7a7e3SShri Abhyankar 
1802dc7a7e3SShri Abhyankar   PetscFunctionBegin;
1816427ac75SLisandro Dalcin   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
1820a82b154SShri   if (nevents) {
183064a246eSJacob Faibussowitsch     PetscValidIntPointer(direction, 3);
184064a246eSJacob Faibussowitsch     PetscValidBoolPointer(terminate, 4);
1850a82b154SShri   }
1866427ac75SLisandro Dalcin 
187*4dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&event));
1889566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nevents, &event->fvalue));
1899566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nevents, &event->fvalue_prev));
1909566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nevents, &event->fvalue_right));
1919566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nevents, &event->zerocrossing));
1929566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nevents, &event->side));
1939566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nevents, &event->direction));
1949566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nevents, &event->terminate));
1959566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nevents, &event->vtol));
196d94325d3SShri Abhyankar   for (i = 0; i < nevents; i++) {
197d94325d3SShri Abhyankar     event->direction[i]    = direction[i];
198d94325d3SShri Abhyankar     event->terminate[i]    = terminate[i];
199e2cdd850SShri Abhyankar     event->zerocrossing[i] = PETSC_FALSE;
200e2cdd850SShri Abhyankar     event->side[i]         = 0;
201d94325d3SShri Abhyankar   }
2029566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nevents, &event->events_zero));
2032589fa24SLisandro Dalcin   event->nevents                    = nevents;
2046427ac75SLisandro Dalcin   event->eventhandler               = eventhandler;
2052dc7a7e3SShri Abhyankar   event->postevent                  = postevent;
2066427ac75SLisandro Dalcin   event->ctx                        = ctx;
207458122a4SShri Abhyankar   event->timestep_posteventinterval = ts->time_step;
2089566063dSJacob Faibussowitsch   PetscCall(TSGetAdapt(ts, &adapt));
2099566063dSJacob Faibussowitsch   PetscCall(TSAdaptGetStepLimits(adapt, &hmin, NULL));
210d294eb03SHong Zhang   event->timestep_min = hmin;
2112dc7a7e3SShri Abhyankar 
21202749585SLisandro Dalcin   event->recsize = 8; /* Initial size of the recorder */
213d0609cedSBarry Smith   PetscOptionsBegin(((PetscObject)ts)->comm, ((PetscObject)ts)->prefix, "TS Event options", "TS");
2142dc7a7e3SShri Abhyankar   {
2159566063dSJacob Faibussowitsch     PetscCall(PetscOptionsReal("-ts_event_tol", "Scalar event tolerance for zero crossing check", "TSSetEventTolerances", tol, &tol, NULL));
2169566063dSJacob Faibussowitsch     PetscCall(PetscOptionsName("-ts_event_monitor", "Print choices made by event handler", "", &flg));
2179566063dSJacob Faibussowitsch     PetscCall(PetscOptionsInt("-ts_event_recorder_initial_size", "Initial size of event recorder", "", event->recsize, &event->recsize, NULL));
2189566063dSJacob Faibussowitsch     PetscCall(PetscOptionsReal("-ts_event_post_eventinterval_step", "Time step after event interval", "", event->timestep_posteventinterval, &event->timestep_posteventinterval, NULL));
2199566063dSJacob Faibussowitsch     PetscCall(PetscOptionsReal("-ts_event_post_event_step", "Time step after event", "", event->timestep_postevent, &event->timestep_postevent, NULL));
2209566063dSJacob Faibussowitsch     PetscCall(PetscOptionsReal("-ts_event_dt_min", "Minimum time step considered for TSEvent", "", event->timestep_min, &event->timestep_min, NULL));
2212dc7a7e3SShri Abhyankar   }
222d0609cedSBarry Smith   PetscOptionsEnd();
223a4ffd976SShri Abhyankar 
2249566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(event->recsize, &event->recorder.time));
2259566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(event->recsize, &event->recorder.stepnum));
2269566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(event->recsize, &event->recorder.nevents));
2279566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(event->recsize, &event->recorder.eventidx));
22848a46eb9SPierre Jolivet   for (i = 0; i < event->recsize; i++) PetscCall(PetscMalloc1(event->nevents, &event->recorder.eventidx[i]));
229e7069c78SShri   /* Initialize the event recorder */
230e7069c78SShri   event->recorder.ctr = 0;
231a4ffd976SShri Abhyankar 
232e3005195SShri Abhyankar   for (i = 0; i < event->nevents; i++) event->vtol[i] = tol;
2339566063dSJacob Faibussowitsch   if (flg) PetscCall(PetscViewerASCIIOpen(PETSC_COMM_SELF, "stdout", &event->monitor));
2349e12be75SShri Abhyankar 
2359566063dSJacob Faibussowitsch   PetscCall(TSEventDestroy(&ts->event));
236d94325d3SShri Abhyankar   ts->event        = event;
237e7069c78SShri   ts->event->refct = 1;
2382dc7a7e3SShri Abhyankar   PetscFunctionReturn(0);
2392dc7a7e3SShri Abhyankar }
2402dc7a7e3SShri Abhyankar 
241a4ffd976SShri Abhyankar /*
242a4ffd976SShri Abhyankar   TSEventRecorderResize - Resizes (2X) the event recorder arrays whenever the recording limit (event->recsize)
243a4ffd976SShri Abhyankar                           is reached.
244a4ffd976SShri Abhyankar */
2459371c9d4SSatish Balay static PetscErrorCode TSEventRecorderResize(TSEvent event) {
246a4ffd976SShri Abhyankar   PetscReal *time;
247a4ffd976SShri Abhyankar   PetscInt  *stepnum;
248a4ffd976SShri Abhyankar   PetscInt  *nevents;
249a4ffd976SShri Abhyankar   PetscInt **eventidx;
250a4ffd976SShri Abhyankar   PetscInt   i, fact = 2;
251a4ffd976SShri Abhyankar 
252a4ffd976SShri Abhyankar   PetscFunctionBegin;
253a4ffd976SShri Abhyankar 
254a4ffd976SShri Abhyankar   /* Create large arrays */
2559566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(fact * event->recsize, &time));
2569566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(fact * event->recsize, &stepnum));
2579566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(fact * event->recsize, &nevents));
2589566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(fact * event->recsize, &eventidx));
25948a46eb9SPierre Jolivet   for (i = 0; i < fact * event->recsize; i++) PetscCall(PetscMalloc1(event->nevents, &eventidx[i]));
260a4ffd976SShri Abhyankar 
261a4ffd976SShri Abhyankar   /* Copy over data */
2629566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(time, event->recorder.time, event->recsize));
2639566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(stepnum, event->recorder.stepnum, event->recsize));
2649566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(nevents, event->recorder.nevents, event->recsize));
26548a46eb9SPierre Jolivet   for (i = 0; i < event->recsize; i++) PetscCall(PetscArraycpy(eventidx[i], event->recorder.eventidx[i], event->recorder.nevents[i]));
266a4ffd976SShri Abhyankar 
267a4ffd976SShri Abhyankar   /* Destroy old arrays */
26848a46eb9SPierre Jolivet   for (i = 0; i < event->recsize; i++) PetscCall(PetscFree(event->recorder.eventidx[i]));
2699566063dSJacob Faibussowitsch   PetscCall(PetscFree(event->recorder.eventidx));
2709566063dSJacob Faibussowitsch   PetscCall(PetscFree(event->recorder.nevents));
2719566063dSJacob Faibussowitsch   PetscCall(PetscFree(event->recorder.stepnum));
2729566063dSJacob Faibussowitsch   PetscCall(PetscFree(event->recorder.time));
273a4ffd976SShri Abhyankar 
274a4ffd976SShri Abhyankar   /* Set pointers */
275a4ffd976SShri Abhyankar   event->recorder.time     = time;
276a4ffd976SShri Abhyankar   event->recorder.stepnum  = stepnum;
277a4ffd976SShri Abhyankar   event->recorder.nevents  = nevents;
278a4ffd976SShri Abhyankar   event->recorder.eventidx = eventidx;
279a4ffd976SShri Abhyankar 
280a4ffd976SShri Abhyankar   /* Double size */
281a4ffd976SShri Abhyankar   event->recsize *= fact;
282a4ffd976SShri Abhyankar 
283a4ffd976SShri Abhyankar   PetscFunctionReturn(0);
284a4ffd976SShri Abhyankar }
285a4ffd976SShri Abhyankar 
286031fbad4SShri Abhyankar /*
287ac6a796dSBarry Smith    Helper routine to handle user postevents and recording
288031fbad4SShri Abhyankar */
2899371c9d4SSatish Balay static PetscErrorCode TSPostEvent(TS ts, PetscReal t, Vec U) {
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));
3019566063dSJacob Faibussowitsch     PetscCall((*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 
3184597913aSLisandro Dalcin   /* Reset event residual functions as states might get changed by the postevent callback */
319f443add6SLisandro Dalcin   if (event->postevent) {
3209566063dSJacob Faibussowitsch     PetscCall(VecLockReadPush(U));
3219566063dSJacob Faibussowitsch     PetscCall((*event->eventhandler)(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++;
3382dc7a7e3SShri Abhyankar   PetscFunctionReturn(0);
3392dc7a7e3SShri Abhyankar }
3402dc7a7e3SShri Abhyankar 
34102749585SLisandro Dalcin /* Uses Anderson-Bjorck variant of regula falsi method */
3429371c9d4SSatish Balay static inline PetscReal TSEventComputeStepSize(PetscReal tleft, PetscReal t, PetscReal tright, PetscScalar fleft, PetscScalar f, PetscScalar fright, PetscInt side, PetscReal dt) {
34302749585SLisandro Dalcin   PetscReal new_dt, scal = 1.0;
344e2cdd850SShri Abhyankar   if (PetscRealPart(fleft) * PetscRealPart(f) < 0) {
345e2cdd850SShri Abhyankar     if (side == 1) {
346a6c783d2SShri Abhyankar       scal = (PetscRealPart(fright) - PetscRealPart(f)) / PetscRealPart(fright);
347a6c783d2SShri Abhyankar       if (scal < PETSC_SMALL) scal = 0.5;
348e2cdd850SShri Abhyankar     }
34902749585SLisandro Dalcin     new_dt = (scal * PetscRealPart(fleft) * t - PetscRealPart(f) * tleft) / (scal * PetscRealPart(fleft) - PetscRealPart(f)) - tleft;
350e2cdd850SShri Abhyankar   } else {
351e2cdd850SShri Abhyankar     if (side == -1) {
352a6c783d2SShri Abhyankar       scal = (PetscRealPart(fleft) - PetscRealPart(f)) / PetscRealPart(fleft);
353a6c783d2SShri Abhyankar       if (scal < PETSC_SMALL) scal = 0.5;
354e2cdd850SShri Abhyankar     }
35502749585SLisandro Dalcin     new_dt = (PetscRealPart(f) * tright - scal * PetscRealPart(fright) * t) / (PetscRealPart(f) - scal * PetscRealPart(fright)) - t;
356e2cdd850SShri Abhyankar   }
35702749585SLisandro Dalcin   return PetscMin(dt, new_dt);
35838bf2713SShri Abhyankar }
359e2cdd850SShri Abhyankar 
3609371c9d4SSatish Balay static PetscErrorCode TSEventDetection(TS ts) {
361d294eb03SHong Zhang   TSEvent   event = ts->event;
362d294eb03SHong Zhang   PetscReal t;
363d294eb03SHong Zhang   PetscInt  i;
364d294eb03SHong Zhang   PetscInt  fvalue_sign, fvalueprev_sign;
365ea3dac1cSHong Zhang   PetscInt  in, out;
366d294eb03SHong Zhang 
367d294eb03SHong Zhang   PetscFunctionBegin;
3689566063dSJacob Faibussowitsch   PetscCall(TSGetTime(ts, &t));
369d294eb03SHong Zhang   for (i = 0; i < event->nevents; i++) {
370d294eb03SHong Zhang     if (PetscAbsScalar(event->fvalue[i]) < event->vtol[i]) {
371d294eb03SHong Zhang       if (!event->iterctr) event->zerocrossing[i] = PETSC_TRUE;
372d294eb03SHong Zhang       event->status = TSEVENT_LOCATED_INTERVAL;
373d294eb03SHong Zhang       if (event->monitor) {
37463a3b9bcSJacob 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));
375d294eb03SHong Zhang       }
376d294eb03SHong Zhang       continue;
377d294eb03SHong Zhang     }
378ea3dac1cSHong Zhang     if (PetscAbsScalar(event->fvalue_prev[i]) < event->vtol[i]) continue; /* avoid duplicative detection if the previous endpoint is an event location */
379d294eb03SHong Zhang     fvalue_sign     = PetscSign(PetscRealPart(event->fvalue[i]));
380d294eb03SHong Zhang     fvalueprev_sign = PetscSign(PetscRealPart(event->fvalue_prev[i]));
381d294eb03SHong Zhang     if (fvalueprev_sign != 0 && (fvalue_sign != fvalueprev_sign)) {
382d294eb03SHong Zhang       if (!event->iterctr) event->zerocrossing[i] = PETSC_TRUE;
383d294eb03SHong Zhang       event->status = TSEVENT_LOCATED_INTERVAL;
38448a46eb9SPierre 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));
385d294eb03SHong Zhang     }
386d294eb03SHong Zhang   }
387d5f990dbSBarry Smith   in = (PetscInt)event->status;
3881c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&in, &out, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)ts)));
389ea3dac1cSHong Zhang   event->status = (TSEventStatus)out;
390d294eb03SHong Zhang   PetscFunctionReturn(0);
391d294eb03SHong Zhang }
392d294eb03SHong Zhang 
3939371c9d4SSatish Balay static PetscErrorCode TSEventLocation(TS ts, PetscReal *dt) {
394d294eb03SHong Zhang   TSEvent   event = ts->event;
395d294eb03SHong Zhang   PetscInt  i;
396d294eb03SHong Zhang   PetscReal t;
397ea3dac1cSHong Zhang   PetscInt  fvalue_sign, fvalueprev_sign;
398ea3dac1cSHong Zhang   PetscInt  rollback = 0, in[2], out[2];
399d294eb03SHong Zhang 
400d294eb03SHong Zhang   PetscFunctionBegin;
4019566063dSJacob Faibussowitsch   PetscCall(TSGetTime(ts, &t));
402d294eb03SHong Zhang   event->nevents_zero = 0;
403d294eb03SHong Zhang   for (i = 0; i < event->nevents; i++) {
404d294eb03SHong Zhang     if (event->zerocrossing[i]) {
405d294eb03SHong Zhang       if (PetscAbsScalar(event->fvalue[i]) < event->vtol[i] || *dt < event->timestep_min || PetscAbsReal((*dt) / ((event->ptime_right - event->ptime_prev) / 2)) < event->vtol[i]) { /* stopping criteria */
406d294eb03SHong Zhang         event->status          = TSEVENT_ZERO;
407d294eb03SHong Zhang         event->fvalue_right[i] = event->fvalue[i];
408d294eb03SHong Zhang         continue;
409d294eb03SHong Zhang       }
410d294eb03SHong Zhang       /* Compute new time step */
411d294eb03SHong 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);
412d294eb03SHong Zhang       fvalue_sign     = PetscSign(PetscRealPart(event->fvalue[i]));
413ea3dac1cSHong Zhang       fvalueprev_sign = PetscSign(PetscRealPart(event->fvalue_prev[i]));
414d294eb03SHong Zhang       switch (event->direction[i]) {
415d294eb03SHong Zhang       case -1:
416d294eb03SHong Zhang         if (fvalue_sign < 0) {
417ea3dac1cSHong Zhang           rollback               = 1;
418d294eb03SHong Zhang           event->fvalue_right[i] = event->fvalue[i];
419d294eb03SHong Zhang           event->side[i]         = 1;
420d294eb03SHong Zhang         }
421d294eb03SHong Zhang         break;
422d294eb03SHong Zhang       case 1:
423d294eb03SHong Zhang         if (fvalue_sign > 0) {
424ea3dac1cSHong Zhang           rollback               = 1;
425d294eb03SHong Zhang           event->fvalue_right[i] = event->fvalue[i];
426d294eb03SHong Zhang           event->side[i]         = 1;
427d294eb03SHong Zhang         }
428d294eb03SHong Zhang         break;
429d294eb03SHong Zhang       case 0:
430ea3dac1cSHong Zhang         if (fvalue_sign != fvalueprev_sign) { /* trigger rollback only when there is a sign change */
431ea3dac1cSHong Zhang           rollback               = 1;
432d294eb03SHong Zhang           event->fvalue_right[i] = event->fvalue[i];
433d294eb03SHong Zhang           event->side[i]         = 1;
434ea3dac1cSHong Zhang         }
435d294eb03SHong Zhang         break;
436d294eb03SHong Zhang       }
437ea3dac1cSHong Zhang       if (event->status == TSEVENT_PROCESSING) event->side[i] = -1;
438d294eb03SHong Zhang     }
439d294eb03SHong Zhang   }
4409371c9d4SSatish Balay   in[0] = (PetscInt)event->status;
4419371c9d4SSatish Balay   in[1] = rollback;
4421c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(in, out, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)ts)));
4439371c9d4SSatish Balay   event->status = (TSEventStatus)out[0];
4449371c9d4SSatish Balay   rollback      = out[1];
445ea3dac1cSHong Zhang   /* 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 corret order */
446ea3dac1cSHong Zhang   if (rollback) event->status = TSEVENT_LOCATED_INTERVAL;
447d294eb03SHong Zhang   if (event->status == TSEVENT_ZERO) {
448ea3dac1cSHong Zhang     for (i = 0; i < event->nevents; i++) {
449ea3dac1cSHong Zhang       if (event->zerocrossing[i]) {
450ea3dac1cSHong Zhang         if (PetscAbsScalar(event->fvalue[i]) < event->vtol[i] || *dt < event->timestep_min || PetscAbsReal((*dt) / ((event->ptime_right - event->ptime_prev) / 2)) < event->vtol[i]) { /* stopping criteria */
451ea3dac1cSHong Zhang           event->events_zero[event->nevents_zero++] = i;
45248a46eb9SPierre 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));
453ea3dac1cSHong Zhang           event->zerocrossing[i] = PETSC_FALSE;
454ea3dac1cSHong Zhang         }
455ea3dac1cSHong Zhang       }
456ea3dac1cSHong Zhang       event->side[i] = 0;
457ea3dac1cSHong Zhang     }
458d294eb03SHong Zhang   }
459d294eb03SHong Zhang   PetscFunctionReturn(0);
460d294eb03SHong Zhang }
46138bf2713SShri Abhyankar 
4629371c9d4SSatish Balay PetscErrorCode TSEventHandler(TS ts) {
4636427ac75SLisandro Dalcin   TSEvent   event;
4642dc7a7e3SShri Abhyankar   PetscReal t;
4652dc7a7e3SShri Abhyankar   Vec       U;
4662dc7a7e3SShri Abhyankar   PetscInt  i;
467ea3dac1cSHong Zhang   PetscReal dt, dt_min, dt_reset = 0.0;
4682dc7a7e3SShri Abhyankar 
4692dc7a7e3SShri Abhyankar   PetscFunctionBegin;
4706427ac75SLisandro Dalcin   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
4716427ac75SLisandro Dalcin   if (!ts->event) PetscFunctionReturn(0);
4726427ac75SLisandro Dalcin   event = ts->event;
4732dc7a7e3SShri Abhyankar 
4749566063dSJacob Faibussowitsch   PetscCall(TSGetTime(ts, &t));
4759566063dSJacob Faibussowitsch   PetscCall(TSGetTimeStep(ts, &dt));
4769566063dSJacob Faibussowitsch   PetscCall(TSGetSolution(ts, &U));
4772dc7a7e3SShri Abhyankar 
4787dbe0728SLisandro Dalcin   if (event->status == TSEVENT_NONE) {
4797dbe0728SLisandro Dalcin     event->timestep_prev = dt;
480d294eb03SHong Zhang     event->ptime_end     = t;
4817dbe0728SLisandro Dalcin   }
4822dc7a7e3SShri Abhyankar   if (event->status == TSEVENT_RESET_NEXTSTEP) {
483d294eb03SHong Zhang     /* user has specified a PostEventInterval dt */
484458122a4SShri Abhyankar     dt = event->timestep_posteventinterval;
485e97c63d7SStefano Zampini     if (ts->exact_final_time == TS_EXACTFINALTIME_MATCHSTEP) {
486e97c63d7SStefano Zampini       PetscReal maxdt = ts->max_time - t;
487e97c63d7SStefano Zampini       dt              = dt > maxdt ? maxdt : (PetscIsCloseAtTol(dt, maxdt, 10 * PETSC_MACHINE_EPSILON, 0) ? maxdt : dt);
488e97c63d7SStefano Zampini     }
4899566063dSJacob Faibussowitsch     PetscCall(TSSetTimeStep(ts, dt));
4902dc7a7e3SShri Abhyankar     event->status = TSEVENT_NONE;
4912dc7a7e3SShri Abhyankar   }
4922dc7a7e3SShri Abhyankar 
4939566063dSJacob Faibussowitsch   PetscCall(VecLockReadPush(U));
4949566063dSJacob Faibussowitsch   PetscCall((*event->eventhandler)(ts, t, U, event->fvalue, event->ctx));
4959566063dSJacob Faibussowitsch   PetscCall(VecLockReadPop(U));
4969e12be75SShri Abhyankar 
497d294eb03SHong Zhang   /* Detect the events */
4989566063dSJacob Faibussowitsch   PetscCall(TSEventDetection(ts));
499d294eb03SHong Zhang 
500d294eb03SHong Zhang   /* Locate the events */
501d294eb03SHong Zhang   if (event->status == TSEVENT_LOCATED_INTERVAL || event->status == TSEVENT_PROCESSING) {
502d294eb03SHong Zhang     /* Approach the zero crosing by setting a new step size */
5039566063dSJacob Faibussowitsch     PetscCall(TSEventLocation(ts, &dt));
504d294eb03SHong Zhang     /* Roll back when new events are detected */
505d294eb03SHong Zhang     if (event->status == TSEVENT_LOCATED_INTERVAL) {
5069566063dSJacob Faibussowitsch       PetscCall(TSRollBack(ts));
5079566063dSJacob Faibussowitsch       PetscCall(TSSetConvergedReason(ts, TS_CONVERGED_ITERATING));
508d294eb03SHong Zhang       event->iterctr++;
509006e6a18SShri Abhyankar     }
5101c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(&dt, &dt_min, 1, MPIU_REAL, MPIU_MIN, PetscObjectComm((PetscObject)ts)));
511ea3dac1cSHong Zhang     if (dt_reset > 0.0 && dt_reset < dt_min) dt_min = dt_reset;
5129566063dSJacob Faibussowitsch     PetscCall(TSSetTimeStep(ts, dt_min));
513d294eb03SHong Zhang     /* Found the zero crossing */
5149e12be75SShri Abhyankar     if (event->status == TSEVENT_ZERO) {
5159566063dSJacob Faibussowitsch       PetscCall(TSPostEvent(ts, t, U));
5169e12be75SShri Abhyankar 
517e2cdd850SShri Abhyankar       dt = event->ptime_end - t;
518ad508104SStefano Zampini       if (PetscAbsReal(dt) < PETSC_SMALL) { /* we hit the event, continue with the candidate time step */
519ad508104SStefano Zampini         dt            = event->timestep_prev;
520ad508104SStefano Zampini         event->status = TSEVENT_NONE;
521ad508104SStefano Zampini       }
522d294eb03SHong Zhang       if (event->timestep_postevent) { /* user has specified a PostEvent dt*/
523d294eb03SHong Zhang         dt = event->timestep_postevent;
524d294eb03SHong Zhang       }
525e97c63d7SStefano Zampini       if (ts->exact_final_time == TS_EXACTFINALTIME_MATCHSTEP) {
526e97c63d7SStefano Zampini         PetscReal maxdt = ts->max_time - t;
527e97c63d7SStefano Zampini         dt              = dt > maxdt ? maxdt : (PetscIsCloseAtTol(dt, maxdt, 10 * PETSC_MACHINE_EPSILON, 0) ? maxdt : dt);
528e97c63d7SStefano Zampini       }
5299566063dSJacob Faibussowitsch       PetscCall(TSSetTimeStep(ts, dt));
53038bf2713SShri Abhyankar       event->iterctr = 0;
5319e12be75SShri Abhyankar     }
532d294eb03SHong Zhang     /* Have not found the zero crosing yet */
533d294eb03SHong Zhang     if (event->status == TSEVENT_PROCESSING) {
53448a46eb9SPierre 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));
535d294eb03SHong Zhang       event->iterctr++;
536d294eb03SHong Zhang     }
537d294eb03SHong Zhang   }
538d294eb03SHong Zhang   if (event->status == TSEVENT_LOCATED_INTERVAL) { /* The step has been rolled back */
5392dc7a7e3SShri Abhyankar     event->status      = TSEVENT_PROCESSING;
540e2cdd850SShri Abhyankar     event->ptime_right = t;
5412dc7a7e3SShri Abhyankar   } else {
542d294eb03SHong Zhang     for (i = 0; i < event->nevents; i++) event->fvalue_prev[i] = event->fvalue[i];
54338bf2713SShri Abhyankar     event->ptime_prev = t;
54438bf2713SShri Abhyankar   }
5452dc7a7e3SShri Abhyankar   PetscFunctionReturn(0);
5462dc7a7e3SShri Abhyankar }
5472dc7a7e3SShri Abhyankar 
5489371c9d4SSatish Balay PetscErrorCode TSAdjointEventHandler(TS ts) {
5496427ac75SLisandro Dalcin   TSEvent   event;
550d0578d90SShri Abhyankar   PetscReal t;
551d0578d90SShri Abhyankar   Vec       U;
552d0578d90SShri Abhyankar   PetscInt  ctr;
553d0578d90SShri Abhyankar   PetscBool forwardsolve = PETSC_FALSE; /* Flag indicating that TS is doing an adjoint solve */
554d0578d90SShri Abhyankar 
555d0578d90SShri Abhyankar   PetscFunctionBegin;
5566427ac75SLisandro Dalcin   PetscValidHeaderSpecific(ts, TS_CLASSID, 1);
5576427ac75SLisandro Dalcin   if (!ts->event) PetscFunctionReturn(0);
5586427ac75SLisandro Dalcin   event = ts->event;
559d0578d90SShri Abhyankar 
5609566063dSJacob Faibussowitsch   PetscCall(TSGetTime(ts, &t));
5619566063dSJacob Faibussowitsch   PetscCall(TSGetSolution(ts, &U));
562d0578d90SShri Abhyankar 
563d0578d90SShri Abhyankar   ctr = event->recorder.ctr - 1;
564bcbf8bb3SShri Abhyankar   if (ctr >= 0 && PetscAbsReal(t - event->recorder.time[ctr]) < PETSC_SMALL) {
565d0578d90SShri Abhyankar     /* Call the user postevent function */
566d0578d90SShri Abhyankar     if (event->postevent) {
5679566063dSJacob Faibussowitsch       PetscCall((*event->postevent)(ts, event->recorder.nevents[ctr], event->recorder.eventidx[ctr], t, U, forwardsolve, event->ctx));
568d0578d90SShri Abhyankar       event->recorder.ctr--;
569d0578d90SShri Abhyankar     }
570d0578d90SShri Abhyankar   }
571d0578d90SShri Abhyankar 
572d0578d90SShri Abhyankar   PetscBarrier((PetscObject)ts);
573d0578d90SShri Abhyankar   PetscFunctionReturn(0);
574d0578d90SShri Abhyankar }
5751ea83e56SMiguel 
5761ea83e56SMiguel /*@
5771ea83e56SMiguel   TSGetNumEvents - Get the numbers of events set
5781ea83e56SMiguel 
5791ea83e56SMiguel   Logically Collective
5801ea83e56SMiguel 
5814165533cSJose E. Roman   Input Parameter:
58299c90e12SSatish Balay . ts - the TS context
5831ea83e56SMiguel 
5844165533cSJose E. Roman   Output Parameter:
5851ea83e56SMiguel . nevents - number of events
5861ea83e56SMiguel 
5871ea83e56SMiguel   Level: intermediate
5881ea83e56SMiguel 
589db781477SPatrick Sanan .seealso: `TSSetEventHandler()`
5901ea83e56SMiguel 
5911ea83e56SMiguel @*/
5929371c9d4SSatish Balay PetscErrorCode TSGetNumEvents(TS ts, PetscInt *nevents) {
5931ea83e56SMiguel   PetscFunctionBegin;
5941ea83e56SMiguel   *nevents = ts->event->nevents;
5951ea83e56SMiguel   PetscFunctionReturn(0);
5961ea83e56SMiguel }
597