xref: /petsc/src/ts/event/tsevent.c (revision 4165533ce9fbcd1440639b2ad505faa054a49d0c)
1af0996ceSBarry Smith #include <petsc/private/tsimpl.h> /*I  "petscts.h" I*/
22dc7a7e3SShri Abhyankar 
36fea3669SShri Abhyankar /*
46427ac75SLisandro Dalcin   TSEventInitialize - Initializes TSEvent for TSSolve
56fea3669SShri Abhyankar */
66427ac75SLisandro Dalcin PetscErrorCode TSEventInitialize(TSEvent event,TS ts,PetscReal t,Vec U)
76fea3669SShri Abhyankar {
86fea3669SShri Abhyankar   PetscErrorCode ierr;
96fea3669SShri Abhyankar 
106fea3669SShri Abhyankar   PetscFunctionBegin;
116427ac75SLisandro Dalcin   if (!event) PetscFunctionReturn(0);
126427ac75SLisandro Dalcin   PetscValidPointer(event,1);
136427ac75SLisandro Dalcin   PetscValidHeaderSpecific(ts,TS_CLASSID,2);
146427ac75SLisandro Dalcin   PetscValidHeaderSpecific(U,VEC_CLASSID,4);
156fea3669SShri Abhyankar   event->ptime_prev = t;
1638bf2713SShri Abhyankar   event->iterctr = 0;
176427ac75SLisandro Dalcin   ierr = (*event->eventhandler)(ts,t,U,event->fvalue_prev,event->ctx);CHKERRQ(ierr);
186fea3669SShri Abhyankar   PetscFunctionReturn(0);
196fea3669SShri Abhyankar }
206fea3669SShri Abhyankar 
217dbe0728SLisandro Dalcin PetscErrorCode TSEventDestroy(TSEvent *event)
227dbe0728SLisandro Dalcin {
237dbe0728SLisandro Dalcin   PetscErrorCode ierr;
247dbe0728SLisandro Dalcin   PetscInt       i;
257dbe0728SLisandro Dalcin 
267dbe0728SLisandro Dalcin   PetscFunctionBegin;
277dbe0728SLisandro Dalcin   PetscValidPointer(event,1);
287dbe0728SLisandro Dalcin   if (!*event) PetscFunctionReturn(0);
29c793f718SLisandro Dalcin   if (--(*event)->refct > 0) {*event = NULL; PetscFunctionReturn(0);}
30e7069c78SShri 
317dbe0728SLisandro Dalcin   ierr = PetscFree((*event)->fvalue);CHKERRQ(ierr);
327dbe0728SLisandro Dalcin   ierr = PetscFree((*event)->fvalue_prev);CHKERRQ(ierr);
33e2cdd850SShri Abhyankar   ierr = PetscFree((*event)->fvalue_right);CHKERRQ(ierr);
34e2cdd850SShri Abhyankar   ierr = PetscFree((*event)->zerocrossing);CHKERRQ(ierr);
35e2cdd850SShri Abhyankar   ierr = PetscFree((*event)->side);CHKERRQ(ierr);
367dbe0728SLisandro Dalcin   ierr = PetscFree((*event)->direction);CHKERRQ(ierr);
377dbe0728SLisandro Dalcin   ierr = PetscFree((*event)->terminate);CHKERRQ(ierr);
387dbe0728SLisandro Dalcin   ierr = PetscFree((*event)->events_zero);CHKERRQ(ierr);
397dbe0728SLisandro Dalcin   ierr = PetscFree((*event)->vtol);CHKERRQ(ierr);
40a4ffd976SShri Abhyankar 
41a4ffd976SShri Abhyankar   for (i=0; i < (*event)->recsize; i++) {
427dbe0728SLisandro Dalcin     ierr = PetscFree((*event)->recorder.eventidx[i]);CHKERRQ(ierr);
437dbe0728SLisandro Dalcin   }
44a4ffd976SShri Abhyankar   ierr = PetscFree((*event)->recorder.eventidx);CHKERRQ(ierr);
45a4ffd976SShri Abhyankar   ierr = PetscFree((*event)->recorder.nevents);CHKERRQ(ierr);
46a4ffd976SShri Abhyankar   ierr = PetscFree((*event)->recorder.stepnum);CHKERRQ(ierr);
47a4ffd976SShri Abhyankar   ierr = PetscFree((*event)->recorder.time);CHKERRQ(ierr);
48a4ffd976SShri Abhyankar 
497dbe0728SLisandro Dalcin   ierr = PetscViewerDestroy(&(*event)->monitor);CHKERRQ(ierr);
507dbe0728SLisandro Dalcin   ierr = PetscFree(*event);CHKERRQ(ierr);
517dbe0728SLisandro Dalcin   PetscFunctionReturn(0);
527dbe0728SLisandro Dalcin }
537dbe0728SLisandro Dalcin 
54e3005195SShri Abhyankar /*@
55ac6a796dSBarry Smith   TSSetPostEventIntervalStep - Set the time-step used immediately following the event interval
56458122a4SShri Abhyankar 
57458122a4SShri Abhyankar   Logically Collective
58458122a4SShri Abhyankar 
59*4165533cSJose E. Roman   Input Parameters:
60458122a4SShri Abhyankar + ts - time integration context
61458122a4SShri Abhyankar - dt - post event interval step
62458122a4SShri Abhyankar 
63458122a4SShri Abhyankar   Options Database Keys:
64458122a4SShri Abhyankar . -ts_event_post_eventinterval_step <dt> time-step after event interval
65458122a4SShri Abhyankar 
66458122a4SShri Abhyankar   Notes:
67ac6a796dSBarry Smith   TSSetPostEventIntervalStep allows one to set a time-step that is used immediately following an event interval.
68458122a4SShri Abhyankar 
69458122a4SShri Abhyankar   This function should be called from the postevent function set with TSSetEventHandler().
70458122a4SShri Abhyankar 
71458122a4SShri Abhyankar   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 
75458122a4SShri Abhyankar   Level: Advanced
76458122a4SShri Abhyankar   .seealso: TS, TSEvent, TSSetEventHandler()
77458122a4SShri Abhyankar @*/
78458122a4SShri Abhyankar PetscErrorCode TSSetPostEventIntervalStep(TS ts,PetscReal dt)
79458122a4SShri Abhyankar {
80458122a4SShri Abhyankar   PetscFunctionBegin;
81458122a4SShri Abhyankar   ts->event->timestep_posteventinterval = dt;
82458122a4SShri Abhyankar   PetscFunctionReturn(0);
83458122a4SShri Abhyankar }
84458122a4SShri Abhyankar 
85458122a4SShri Abhyankar /*@
86e3005195SShri Abhyankar    TSSetEventTolerances - Set tolerances for event zero crossings when using event handler
87e3005195SShri Abhyankar 
88e3005195SShri Abhyankar    Logically Collective
89e3005195SShri Abhyankar 
90*4165533cSJose E. Roman    Input Parameters:
91e3005195SShri Abhyankar +  ts - time integration context
92e3005195SShri Abhyankar .  tol - scalar tolerance, PETSC_DECIDE to leave current value
93e3005195SShri Abhyankar -  vtol - array of tolerances or NULL, used in preference to tol if present
94e3005195SShri Abhyankar 
952589fa24SLisandro Dalcin    Options Database Keys:
962589fa24SLisandro Dalcin .  -ts_event_tol <tol> tolerance for event zero crossing
97e3005195SShri Abhyankar 
98e3005195SShri Abhyankar    Notes:
99f25fe674SLisandro Dalcin    Must call TSSetEventHandler() before setting the tolerances.
100e3005195SShri Abhyankar 
101e3005195SShri Abhyankar    The size of vtol is equal to the number of events.
102e3005195SShri Abhyankar 
103e3005195SShri Abhyankar    Level: beginner
104e3005195SShri Abhyankar 
105f25fe674SLisandro Dalcin .seealso: TS, TSEvent, TSSetEventHandler()
106e3005195SShri Abhyankar @*/
1076427ac75SLisandro Dalcin PetscErrorCode TSSetEventTolerances(TS ts,PetscReal tol,PetscReal vtol[])
108e3005195SShri Abhyankar {
1096427ac75SLisandro Dalcin   TSEvent        event;
110e3005195SShri Abhyankar   PetscInt       i;
111e3005195SShri Abhyankar 
112e3005195SShri Abhyankar   PetscFunctionBegin;
1136427ac75SLisandro Dalcin   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1146427ac75SLisandro Dalcin   if (vtol) PetscValidRealPointer(vtol,3);
115f25fe674SLisandro Dalcin   if (!ts->event) SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_USER,"Must set the events first by calling TSSetEventHandler()");
1166427ac75SLisandro Dalcin 
1176427ac75SLisandro Dalcin   event = ts->event;
118e3005195SShri Abhyankar   if (vtol) {
119e3005195SShri Abhyankar     for (i=0; i < event->nevents; i++) event->vtol[i] = vtol[i];
120e3005195SShri Abhyankar   } else {
121e3005195SShri Abhyankar     if (tol != PETSC_DECIDE || tol != PETSC_DEFAULT) {
122e3005195SShri Abhyankar       for (i=0; i < event->nevents; i++) event->vtol[i] = tol;
123e3005195SShri Abhyankar     }
124e3005195SShri Abhyankar   }
125e3005195SShri Abhyankar   PetscFunctionReturn(0);
126e3005195SShri Abhyankar }
127e3005195SShri Abhyankar 
1282dc7a7e3SShri Abhyankar /*@C
129ac6a796dSBarry Smith    TSSetEventHandler - Sets a function used for detecting events
1302dc7a7e3SShri Abhyankar 
1312dc7a7e3SShri Abhyankar    Logically Collective on TS
1322dc7a7e3SShri Abhyankar 
1332dc7a7e3SShri Abhyankar    Input Parameters:
1342dc7a7e3SShri Abhyankar +  ts - the TS context obtained from TSCreate()
1352dc7a7e3SShri Abhyankar .  nevents - number of local events
136d94325d3SShri Abhyankar .  direction - direction of zero crossing to be detected. -1 => Zero crossing in negative direction,
137d94325d3SShri Abhyankar                +1 => Zero crossing in positive direction, 0 => both ways (one for each event)
138d94325d3SShri Abhyankar .  terminate - flag to indicate whether time stepping should be terminated after
139d94325d3SShri Abhyankar                event is detected (one for each event)
1406427ac75SLisandro Dalcin .  eventhandler - event monitoring routine
1412dc7a7e3SShri Abhyankar .  postevent - [optional] post-event function
1422589fa24SLisandro Dalcin -  ctx       - [optional] user-defined context for private data for the
1432dc7a7e3SShri Abhyankar                event monitor and post event routine (use NULL if no
1442dc7a7e3SShri Abhyankar                context is desired)
1452dc7a7e3SShri Abhyankar 
1466427ac75SLisandro Dalcin    Calling sequence of eventhandler:
1473a88037aSBarry Smith    PetscErrorCode PetscEventHandler(TS ts,PetscReal t,Vec U,PetscScalar fvalue[],void* ctx)
1482dc7a7e3SShri Abhyankar 
1492dc7a7e3SShri Abhyankar    Input Parameters:
1502dc7a7e3SShri Abhyankar +  ts  - the TS context
1512dc7a7e3SShri Abhyankar .  t   - current time
1522dc7a7e3SShri Abhyankar .  U   - current iterate
1536427ac75SLisandro Dalcin -  ctx - [optional] context passed with eventhandler
1542dc7a7e3SShri Abhyankar 
1552dc7a7e3SShri Abhyankar    Output parameters:
156d94325d3SShri Abhyankar .  fvalue    - function value of events at time t
1572dc7a7e3SShri Abhyankar 
1582dc7a7e3SShri Abhyankar    Calling sequence of postevent:
1592589fa24SLisandro Dalcin    PetscErrorCode PostEvent(TS ts,PetscInt nevents_zero,PetscInt events_zero[],PetscReal t,Vec U,PetscBool forwardsolve,void* ctx)
1602dc7a7e3SShri Abhyankar 
1612dc7a7e3SShri Abhyankar    Input Parameters:
1622dc7a7e3SShri Abhyankar +  ts - the TS context
1632dc7a7e3SShri Abhyankar .  nevents_zero - number of local events whose event function is zero
1642dc7a7e3SShri Abhyankar .  events_zero  - indices of local events which have reached zero
1652dc7a7e3SShri Abhyankar .  t            - current time
1662dc7a7e3SShri Abhyankar .  U            - current solution
167031fbad4SShri Abhyankar .  forwardsolve - Flag to indicate whether TS is doing a forward solve (1) or adjoint solve (0)
1686427ac75SLisandro Dalcin -  ctx          - the context passed with eventhandler
1692dc7a7e3SShri Abhyankar 
1702dc7a7e3SShri Abhyankar    Level: intermediate
1712dc7a7e3SShri Abhyankar 
1722dc7a7e3SShri Abhyankar .seealso: TSCreate(), TSSetTimeStep(), TSSetConvergedReason()
1732dc7a7e3SShri Abhyankar @*/
1742589fa24SLisandro Dalcin 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)
1752dc7a7e3SShri Abhyankar {
1762dc7a7e3SShri Abhyankar   PetscErrorCode ierr;
177d294eb03SHong Zhang   TSAdapt        adapt;
178d294eb03SHong Zhang   PetscReal      hmin;
1792dc7a7e3SShri Abhyankar   TSEvent        event;
180d94325d3SShri Abhyankar   PetscInt       i;
181006e6a18SShri Abhyankar   PetscBool      flg;
182a6c783d2SShri Abhyankar #if defined PETSC_USE_REAL_SINGLE
183a6c783d2SShri Abhyankar   PetscReal      tol=1e-4;
184a6c783d2SShri Abhyankar #else
185d569cc17SSatish Balay   PetscReal      tol=1e-6;
186a6c783d2SShri Abhyankar #endif
1872dc7a7e3SShri Abhyankar 
1882dc7a7e3SShri Abhyankar   PetscFunctionBegin;
1896427ac75SLisandro Dalcin   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1900a82b154SShri   if (nevents) {
191064a246eSJacob Faibussowitsch     PetscValidIntPointer(direction,3);
192064a246eSJacob Faibussowitsch     PetscValidBoolPointer(terminate,4);
1930a82b154SShri   }
1946427ac75SLisandro Dalcin 
1956427ac75SLisandro Dalcin   ierr = PetscNewLog(ts,&event);CHKERRQ(ierr);
196854ce69bSBarry Smith   ierr = PetscMalloc1(nevents,&event->fvalue);CHKERRQ(ierr);
197854ce69bSBarry Smith   ierr = PetscMalloc1(nevents,&event->fvalue_prev);CHKERRQ(ierr);
198e2cdd850SShri Abhyankar   ierr = PetscMalloc1(nevents,&event->fvalue_right);CHKERRQ(ierr);
199e2cdd850SShri Abhyankar   ierr = PetscMalloc1(nevents,&event->zerocrossing);CHKERRQ(ierr);
200e2cdd850SShri Abhyankar   ierr = PetscMalloc1(nevents,&event->side);CHKERRQ(ierr);
201854ce69bSBarry Smith   ierr = PetscMalloc1(nevents,&event->direction);CHKERRQ(ierr);
202854ce69bSBarry Smith   ierr = PetscMalloc1(nevents,&event->terminate);CHKERRQ(ierr);
203e3005195SShri Abhyankar   ierr = PetscMalloc1(nevents,&event->vtol);CHKERRQ(ierr);
204d94325d3SShri Abhyankar   for (i=0; i < nevents; i++) {
205d94325d3SShri Abhyankar     event->direction[i] = direction[i];
206d94325d3SShri Abhyankar     event->terminate[i] = terminate[i];
207e2cdd850SShri Abhyankar     event->zerocrossing[i] = PETSC_FALSE;
208e2cdd850SShri Abhyankar     event->side[i] = 0;
209d94325d3SShri Abhyankar   }
210854ce69bSBarry Smith   ierr = PetscMalloc1(nevents,&event->events_zero);CHKERRQ(ierr);
2112589fa24SLisandro Dalcin   event->nevents = nevents;
2126427ac75SLisandro Dalcin   event->eventhandler = eventhandler;
2132dc7a7e3SShri Abhyankar   event->postevent = postevent;
2146427ac75SLisandro Dalcin   event->ctx = ctx;
215458122a4SShri Abhyankar   event->timestep_posteventinterval = ts->time_step;
216d294eb03SHong Zhang   ierr = TSGetAdapt(ts,&adapt);CHKERRQ(ierr);
217d294eb03SHong Zhang   ierr = TSAdaptGetStepLimits(adapt,&hmin,NULL);CHKERRQ(ierr);
218d294eb03SHong Zhang   event->timestep_min = hmin;
2192dc7a7e3SShri Abhyankar 
22002749585SLisandro Dalcin   event->recsize = 8;  /* Initial size of the recorder */
2215fbebc36SLisandro Dalcin   ierr = PetscOptionsBegin(((PetscObject)ts)->comm,((PetscObject)ts)->prefix,"TS Event options","TS");CHKERRQ(ierr);
2222dc7a7e3SShri Abhyankar   {
22302749585SLisandro Dalcin     ierr = PetscOptionsReal("-ts_event_tol","Scalar event tolerance for zero crossing check","TSSetEventTolerances",tol,&tol,NULL);CHKERRQ(ierr);
224006e6a18SShri Abhyankar     ierr = PetscOptionsName("-ts_event_monitor","Print choices made by event handler","",&flg);CHKERRQ(ierr);
225a4ffd976SShri Abhyankar     ierr = PetscOptionsInt("-ts_event_recorder_initial_size","Initial size of event recorder","",event->recsize,&event->recsize,NULL);CHKERRQ(ierr);
226458122a4SShri Abhyankar     ierr = PetscOptionsReal("-ts_event_post_eventinterval_step","Time step after event interval","",event->timestep_posteventinterval,&event->timestep_posteventinterval,NULL);CHKERRQ(ierr);
227d294eb03SHong Zhang     ierr = PetscOptionsReal("-ts_event_post_event_step","Time step after event","",event->timestep_postevent,&event->timestep_postevent,NULL);CHKERRQ(ierr);
228d294eb03SHong Zhang     ierr = PetscOptionsReal("-ts_event_dt_min","Minimum time step considered for TSEvent","",event->timestep_min,&event->timestep_min,NULL);CHKERRQ(ierr);
2292dc7a7e3SShri Abhyankar   }
230b6518c14SStefano Zampini   ierr = PetscOptionsEnd();CHKERRQ(ierr);
231a4ffd976SShri Abhyankar 
232a4ffd976SShri Abhyankar   ierr = PetscMalloc1(event->recsize,&event->recorder.time);CHKERRQ(ierr);
233a4ffd976SShri Abhyankar   ierr = PetscMalloc1(event->recsize,&event->recorder.stepnum);CHKERRQ(ierr);
234a4ffd976SShri Abhyankar   ierr = PetscMalloc1(event->recsize,&event->recorder.nevents);CHKERRQ(ierr);
235a4ffd976SShri Abhyankar   ierr = PetscMalloc1(event->recsize,&event->recorder.eventidx);CHKERRQ(ierr);
236a4ffd976SShri Abhyankar   for (i=0; i < event->recsize; i++) {
237a4ffd976SShri Abhyankar     ierr = PetscMalloc1(event->nevents,&event->recorder.eventidx[i]);CHKERRQ(ierr);
238a4ffd976SShri Abhyankar   }
239e7069c78SShri   /* Initialize the event recorder */
240e7069c78SShri   event->recorder.ctr = 0;
241a4ffd976SShri Abhyankar 
242e3005195SShri Abhyankar   for (i=0; i < event->nevents; i++) event->vtol[i] = tol;
2436427ac75SLisandro Dalcin   if (flg) {ierr = PetscViewerASCIIOpen(PETSC_COMM_SELF,"stdout",&event->monitor);CHKERRQ(ierr);}
2449e12be75SShri Abhyankar 
2456427ac75SLisandro Dalcin   ierr = TSEventDestroy(&ts->event);CHKERRQ(ierr);
246d94325d3SShri Abhyankar   ts->event = event;
247e7069c78SShri   ts->event->refct = 1;
2482dc7a7e3SShri Abhyankar   PetscFunctionReturn(0);
2492dc7a7e3SShri Abhyankar }
2502dc7a7e3SShri Abhyankar 
251a4ffd976SShri Abhyankar /*
252a4ffd976SShri Abhyankar   TSEventRecorderResize - Resizes (2X) the event recorder arrays whenever the recording limit (event->recsize)
253a4ffd976SShri Abhyankar                           is reached.
254a4ffd976SShri Abhyankar */
25502749585SLisandro Dalcin static PetscErrorCode TSEventRecorderResize(TSEvent event)
256a4ffd976SShri Abhyankar {
257a4ffd976SShri Abhyankar   PetscErrorCode ierr;
258a4ffd976SShri Abhyankar   PetscReal      *time;
259a4ffd976SShri Abhyankar   PetscInt       *stepnum;
260a4ffd976SShri Abhyankar   PetscInt       *nevents;
261a4ffd976SShri Abhyankar   PetscInt       **eventidx;
262a4ffd976SShri Abhyankar   PetscInt       i,fact=2;
263a4ffd976SShri Abhyankar 
264a4ffd976SShri Abhyankar   PetscFunctionBegin;
265a4ffd976SShri Abhyankar 
266a4ffd976SShri Abhyankar   /* Create large arrays */
267a4ffd976SShri Abhyankar   ierr = PetscMalloc1(fact*event->recsize,&time);CHKERRQ(ierr);
268a4ffd976SShri Abhyankar   ierr = PetscMalloc1(fact*event->recsize,&stepnum);CHKERRQ(ierr);
269a4ffd976SShri Abhyankar   ierr = PetscMalloc1(fact*event->recsize,&nevents);CHKERRQ(ierr);
270a4ffd976SShri Abhyankar   ierr = PetscMalloc1(fact*event->recsize,&eventidx);CHKERRQ(ierr);
271a4ffd976SShri Abhyankar   for (i=0; i < fact*event->recsize; i++) {
272a4ffd976SShri Abhyankar     ierr = PetscMalloc1(event->nevents,&eventidx[i]);CHKERRQ(ierr);
273a4ffd976SShri Abhyankar   }
274a4ffd976SShri Abhyankar 
275a4ffd976SShri Abhyankar   /* Copy over data */
276580bdb30SBarry Smith   ierr = PetscArraycpy(time,event->recorder.time,event->recsize);CHKERRQ(ierr);
277580bdb30SBarry Smith   ierr = PetscArraycpy(stepnum,event->recorder.stepnum,event->recsize);CHKERRQ(ierr);
278580bdb30SBarry Smith   ierr = PetscArraycpy(nevents,event->recorder.nevents,event->recsize);CHKERRQ(ierr);
279a4ffd976SShri Abhyankar   for (i=0; i < event->recsize; i++) {
280580bdb30SBarry Smith     ierr = PetscArraycpy(eventidx[i],event->recorder.eventidx[i],event->recorder.nevents[i]);CHKERRQ(ierr);
281a4ffd976SShri Abhyankar   }
282a4ffd976SShri Abhyankar 
283a4ffd976SShri Abhyankar   /* Destroy old arrays */
284a4ffd976SShri Abhyankar   for (i=0; i < event->recsize; i++) {
285a4ffd976SShri Abhyankar     ierr = PetscFree(event->recorder.eventidx[i]);CHKERRQ(ierr);
286a4ffd976SShri Abhyankar   }
287a4ffd976SShri Abhyankar   ierr = PetscFree(event->recorder.eventidx);CHKERRQ(ierr);
288a4ffd976SShri Abhyankar   ierr = PetscFree(event->recorder.nevents);CHKERRQ(ierr);
289a4ffd976SShri Abhyankar   ierr = PetscFree(event->recorder.stepnum);CHKERRQ(ierr);
290a4ffd976SShri Abhyankar   ierr = PetscFree(event->recorder.time);CHKERRQ(ierr);
291a4ffd976SShri Abhyankar 
292a4ffd976SShri Abhyankar   /* Set pointers */
293a4ffd976SShri Abhyankar   event->recorder.time = time;
294a4ffd976SShri Abhyankar   event->recorder.stepnum = stepnum;
295a4ffd976SShri Abhyankar   event->recorder.nevents = nevents;
296a4ffd976SShri Abhyankar   event->recorder.eventidx = eventidx;
297a4ffd976SShri Abhyankar 
298a4ffd976SShri Abhyankar   /* Double size */
299a4ffd976SShri Abhyankar   event->recsize *= fact;
300a4ffd976SShri Abhyankar 
301a4ffd976SShri Abhyankar   PetscFunctionReturn(0);
302a4ffd976SShri Abhyankar }
303a4ffd976SShri Abhyankar 
304031fbad4SShri Abhyankar /*
305ac6a796dSBarry Smith    Helper routine to handle user postevents and recording
306031fbad4SShri Abhyankar */
3074597913aSLisandro Dalcin static PetscErrorCode TSPostEvent(TS ts,PetscReal t,Vec U)
3082dc7a7e3SShri Abhyankar {
3092dc7a7e3SShri Abhyankar   PetscErrorCode ierr;
3102dc7a7e3SShri Abhyankar   TSEvent        event = ts->event;
3112dc7a7e3SShri Abhyankar   PetscBool      terminate = PETSC_FALSE;
31228d5b5d6SLisandro Dalcin   PetscBool      restart = PETSC_FALSE;
313d0578d90SShri Abhyankar   PetscInt       i,ctr,stepnum;
3147324a0ffSLisandro Dalcin   PetscBool      inflag[2],outflag[2];
3154597913aSLisandro Dalcin   PetscBool      forwardsolve = PETSC_TRUE; /* Flag indicating that TS is doing a forward solve */
3162dc7a7e3SShri Abhyankar 
3172dc7a7e3SShri Abhyankar   PetscFunctionBegin;
3182dc7a7e3SShri Abhyankar   if (event->postevent) {
31928d5b5d6SLisandro Dalcin     PetscObjectState state_prev,state_post;
32028d5b5d6SLisandro Dalcin     ierr = PetscObjectStateGet((PetscObject)U,&state_prev);CHKERRQ(ierr);
3214597913aSLisandro Dalcin     ierr = (*event->postevent)(ts,event->nevents_zero,event->events_zero,t,U,forwardsolve,event->ctx);CHKERRQ(ierr);
32228d5b5d6SLisandro Dalcin     ierr = PetscObjectStateGet((PetscObject)U,&state_post);CHKERRQ(ierr);
32328d5b5d6SLisandro Dalcin     if (state_prev != state_post) restart = PETSC_TRUE;
3242dc7a7e3SShri Abhyankar   }
3254597913aSLisandro Dalcin 
32628d5b5d6SLisandro Dalcin   /* Handle termination events and step restart */
32728d5b5d6SLisandro Dalcin   for (i=0; i<event->nevents_zero; i++) if (event->terminate[event->events_zero[i]]) terminate = PETSC_TRUE;
3287324a0ffSLisandro Dalcin   inflag[0] = restart; inflag[1] = terminate;
329820f2d46SBarry Smith   ierr = MPIU_Allreduce(inflag,outflag,2,MPIU_BOOL,MPI_LOR,((PetscObject)ts)->comm);CHKERRMPI(ierr);
3307324a0ffSLisandro Dalcin   restart = outflag[0]; terminate = outflag[1];
3317324a0ffSLisandro Dalcin   if (restart) {ierr = TSRestartStep(ts);CHKERRQ(ierr);}
3327324a0ffSLisandro Dalcin   if (terminate) {ierr = TSSetConvergedReason(ts,TS_CONVERGED_EVENT);CHKERRQ(ierr);}
3337324a0ffSLisandro Dalcin   event->status = terminate ? TSEVENT_NONE : TSEVENT_RESET_NEXTSTEP;
334f7aea88cSShri Abhyankar 
3354597913aSLisandro Dalcin   /* Reset event residual functions as states might get changed by the postevent callback */
336f443add6SLisandro Dalcin   if (event->postevent) {
3378860a134SJunchao Zhang     ierr = VecLockReadPush(U);CHKERRQ(ierr);
338f443add6SLisandro Dalcin     ierr = (*event->eventhandler)(ts,t,U,event->fvalue,event->ctx);CHKERRQ(ierr);
3398860a134SJunchao Zhang     ierr = VecLockReadPop(U);CHKERRQ(ierr);
340f443add6SLisandro Dalcin   }
341f443add6SLisandro Dalcin 
342f443add6SLisandro Dalcin   /* Cache current time and event residual functions */
343f443add6SLisandro Dalcin   event->ptime_prev = t;
344f443add6SLisandro Dalcin   for (i=0; i<event->nevents; i++)
345f443add6SLisandro Dalcin     event->fvalue_prev[i] = event->fvalue[i];
3464597913aSLisandro Dalcin 
347d0578d90SShri Abhyankar   /* Record the event in the event recorder */
34880275a0aSLisandro Dalcin   ierr = TSGetStepNumber(ts,&stepnum);CHKERRQ(ierr);
349f7aea88cSShri Abhyankar   ctr = event->recorder.ctr;
350a4ffd976SShri Abhyankar   if (ctr == event->recsize) {
351a4ffd976SShri Abhyankar     ierr = TSEventRecorderResize(event);CHKERRQ(ierr);
352a4ffd976SShri Abhyankar   }
353f7aea88cSShri Abhyankar   event->recorder.time[ctr] = t;
354d0578d90SShri Abhyankar   event->recorder.stepnum[ctr] = stepnum;
3554597913aSLisandro Dalcin   event->recorder.nevents[ctr] = event->nevents_zero;
3564597913aSLisandro Dalcin   for (i=0; i<event->nevents_zero; i++) event->recorder.eventidx[ctr][i] = event->events_zero[i];
357f7aea88cSShri Abhyankar   event->recorder.ctr++;
3582dc7a7e3SShri Abhyankar   PetscFunctionReturn(0);
3592dc7a7e3SShri Abhyankar }
3602dc7a7e3SShri Abhyankar 
36102749585SLisandro Dalcin /* Uses Anderson-Bjorck variant of regula falsi method */
362a3a8645aSShri Abhyankar PETSC_STATIC_INLINE PetscReal TSEventComputeStepSize(PetscReal tleft,PetscReal t,PetscReal tright,PetscScalar fleft,PetscScalar f,PetscScalar fright,PetscInt side,PetscReal dt)
36338bf2713SShri Abhyankar {
36402749585SLisandro Dalcin   PetscReal new_dt, scal = 1.0;
365e2cdd850SShri Abhyankar   if (PetscRealPart(fleft)*PetscRealPart(f) < 0) {
366e2cdd850SShri Abhyankar     if (side == 1) {
367a6c783d2SShri Abhyankar       scal = (PetscRealPart(fright) - PetscRealPart(f))/PetscRealPart(fright);
368a6c783d2SShri Abhyankar       if (scal < PETSC_SMALL) scal = 0.5;
369e2cdd850SShri Abhyankar     }
37002749585SLisandro Dalcin     new_dt = (scal*PetscRealPart(fleft)*t - PetscRealPart(f)*tleft)/(scal*PetscRealPart(fleft) - PetscRealPart(f)) - tleft;
371e2cdd850SShri Abhyankar   } else {
372e2cdd850SShri Abhyankar     if (side == -1) {
373a6c783d2SShri Abhyankar       scal = (PetscRealPart(fleft) - PetscRealPart(f))/PetscRealPart(fleft);
374a6c783d2SShri Abhyankar       if (scal < PETSC_SMALL) scal = 0.5;
375e2cdd850SShri Abhyankar     }
37602749585SLisandro Dalcin     new_dt = (PetscRealPart(f)*tright - scal*PetscRealPart(fright)*t)/(PetscRealPart(f) - scal*PetscRealPart(fright)) - t;
377e2cdd850SShri Abhyankar   }
37802749585SLisandro Dalcin   return PetscMin(dt,new_dt);
37938bf2713SShri Abhyankar }
380e2cdd850SShri Abhyankar 
381d294eb03SHong Zhang static PetscErrorCode TSEventDetection(TS ts)
382d294eb03SHong Zhang {
383d294eb03SHong Zhang   PetscErrorCode ierr;
384d294eb03SHong Zhang   TSEvent        event = ts->event;
385d294eb03SHong Zhang   PetscReal      t;
386d294eb03SHong Zhang   PetscInt       i;
387d294eb03SHong Zhang   PetscInt       fvalue_sign,fvalueprev_sign;
388ea3dac1cSHong Zhang   PetscInt       in,out;
389d294eb03SHong Zhang 
390d294eb03SHong Zhang   PetscFunctionBegin;
391d294eb03SHong Zhang   ierr = TSGetTime(ts,&t);CHKERRQ(ierr);
392d294eb03SHong Zhang   for (i=0; i < event->nevents; i++) {
393d294eb03SHong Zhang     if (PetscAbsScalar(event->fvalue[i]) < event->vtol[i]) {
394d294eb03SHong Zhang       if (!event->iterctr) event->zerocrossing[i] = PETSC_TRUE;
395d294eb03SHong Zhang       event->status = TSEVENT_LOCATED_INTERVAL;
396d294eb03SHong Zhang       if (event->monitor) {
397ea3dac1cSHong Zhang         ierr = PetscViewerASCIIPrintf(event->monitor,"TSEvent: iter %D - Event %D interval detected due to zero value (tol=%g) [%g - %g]\n",event->iterctr,i,(double)event->vtol[i],(double)event->ptime_prev,(double)t);CHKERRQ(ierr);
398d294eb03SHong Zhang       }
399d294eb03SHong Zhang       continue;
400d294eb03SHong Zhang     }
401ea3dac1cSHong Zhang     if (PetscAbsScalar(event->fvalue_prev[i]) < event->vtol[i]) continue; /* avoid duplicative detection if the previous endpoint is an event location */
402d294eb03SHong Zhang     fvalue_sign = PetscSign(PetscRealPart(event->fvalue[i]));
403d294eb03SHong Zhang     fvalueprev_sign = PetscSign(PetscRealPart(event->fvalue_prev[i]));
404d294eb03SHong Zhang     if (fvalueprev_sign != 0 && (fvalue_sign != fvalueprev_sign)) {
405d294eb03SHong Zhang       if (!event->iterctr) event->zerocrossing[i] = PETSC_TRUE;
406d294eb03SHong Zhang       event->status = TSEVENT_LOCATED_INTERVAL;
407d294eb03SHong Zhang       if (event->monitor) {
408ea3dac1cSHong Zhang         ierr = PetscViewerASCIIPrintf(event->monitor,"TSEvent: iter %D - Event %D interval detected due to sign change [%g - %g]\n",event->iterctr,i,(double)event->ptime_prev,(double)t);CHKERRQ(ierr);
409d294eb03SHong Zhang       }
410d294eb03SHong Zhang     }
411d294eb03SHong Zhang   }
412ea3dac1cSHong Zhang   in = event->status;
413ea3dac1cSHong Zhang   ierr = MPIU_Allreduce(&in,&out,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)ts));CHKERRMPI(ierr);
414ea3dac1cSHong Zhang   event->status = (TSEventStatus)out;
415d294eb03SHong Zhang   PetscFunctionReturn(0);
416d294eb03SHong Zhang }
417d294eb03SHong Zhang 
418d294eb03SHong Zhang static PetscErrorCode TSEventLocation(TS ts,PetscReal *dt)
419d294eb03SHong Zhang {
420d294eb03SHong Zhang   PetscErrorCode ierr;
421d294eb03SHong Zhang   TSEvent        event = ts->event;
422d294eb03SHong Zhang   PetscInt       i;
423d294eb03SHong Zhang   PetscReal      t;
424ea3dac1cSHong Zhang   PetscInt       fvalue_sign,fvalueprev_sign;
425ea3dac1cSHong Zhang   PetscInt       rollback=0,in[2],out[2];
426d294eb03SHong Zhang 
427d294eb03SHong Zhang   PetscFunctionBegin;
428d294eb03SHong Zhang   ierr = TSGetTime(ts,&t);CHKERRQ(ierr);
429d294eb03SHong Zhang   event->nevents_zero = 0;
430d294eb03SHong Zhang   for (i=0; i < event->nevents; i++) {
431d294eb03SHong Zhang     if (event->zerocrossing[i]) {
432d294eb03SHong 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 */
433d294eb03SHong Zhang         event->status = TSEVENT_ZERO;
434d294eb03SHong Zhang         event->fvalue_right[i] = event->fvalue[i];
435d294eb03SHong Zhang         continue;
436d294eb03SHong Zhang       }
437d294eb03SHong Zhang       /* Compute new time step */
438d294eb03SHong 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);
439d294eb03SHong Zhang       fvalue_sign = PetscSign(PetscRealPart(event->fvalue[i]));
440ea3dac1cSHong Zhang       fvalueprev_sign = PetscSign(PetscRealPart(event->fvalue_prev[i]));
441d294eb03SHong Zhang       switch (event->direction[i]) {
442d294eb03SHong Zhang       case -1:
443d294eb03SHong Zhang         if (fvalue_sign < 0) {
444ea3dac1cSHong Zhang           rollback = 1;
445d294eb03SHong Zhang           event->fvalue_right[i] = event->fvalue[i];
446d294eb03SHong Zhang           event->side[i] = 1;
447d294eb03SHong Zhang         }
448d294eb03SHong Zhang         break;
449d294eb03SHong Zhang       case 1:
450d294eb03SHong Zhang         if (fvalue_sign > 0) {
451ea3dac1cSHong Zhang           rollback = 1;
452d294eb03SHong Zhang           event->fvalue_right[i] = event->fvalue[i];
453d294eb03SHong Zhang           event->side[i] = 1;
454d294eb03SHong Zhang         }
455d294eb03SHong Zhang         break;
456d294eb03SHong Zhang       case 0:
457ea3dac1cSHong Zhang         if (fvalue_sign != fvalueprev_sign) { /* trigger rollback only when there is a sign change */
458ea3dac1cSHong Zhang           rollback = 1;
459d294eb03SHong Zhang           event->fvalue_right[i] = event->fvalue[i];
460d294eb03SHong Zhang           event->side[i] = 1;
461ea3dac1cSHong Zhang         }
462d294eb03SHong Zhang         break;
463d294eb03SHong Zhang       }
464ea3dac1cSHong Zhang       if (event->status == TSEVENT_PROCESSING) event->side[i] = -1;
465d294eb03SHong Zhang     }
466d294eb03SHong Zhang   }
467ea3dac1cSHong Zhang   in[0] = event->status; in[1] = rollback;
468ea3dac1cSHong Zhang   ierr = MPIU_Allreduce(in,out,2,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)ts));CHKERRMPI(ierr);
469ea3dac1cSHong Zhang   event->status = (TSEventStatus)out[0]; rollback = out[1];
470ea3dac1cSHong 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 */
471ea3dac1cSHong Zhang   if (rollback) event->status = TSEVENT_LOCATED_INTERVAL;
472d294eb03SHong Zhang   if (event->status == TSEVENT_ZERO) {
473ea3dac1cSHong Zhang     for (i=0; i < event->nevents; i++) {
474ea3dac1cSHong Zhang       if (event->zerocrossing[i]) {
475ea3dac1cSHong 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 */
476ea3dac1cSHong Zhang           event->events_zero[event->nevents_zero++] = i;
477ea3dac1cSHong Zhang           if (event->monitor) {
478ea3dac1cSHong Zhang             ierr = PetscViewerASCIIPrintf(event->monitor,"TSEvent: iter %D - Event %D zero crossing located at time %g\n",event->iterctr,i,(double)t);CHKERRQ(ierr);
479ea3dac1cSHong Zhang           }
480ea3dac1cSHong Zhang           event->zerocrossing[i] = PETSC_FALSE;
481ea3dac1cSHong Zhang         }
482ea3dac1cSHong Zhang       }
483ea3dac1cSHong Zhang       event->side[i] = 0;
484ea3dac1cSHong Zhang     }
485d294eb03SHong Zhang   }
486d294eb03SHong Zhang   PetscFunctionReturn(0);
487d294eb03SHong Zhang }
48838bf2713SShri Abhyankar 
4896427ac75SLisandro Dalcin PetscErrorCode TSEventHandler(TS ts)
4902dc7a7e3SShri Abhyankar {
4912dc7a7e3SShri Abhyankar   PetscErrorCode ierr;
4926427ac75SLisandro Dalcin   TSEvent        event;
4932dc7a7e3SShri Abhyankar   PetscReal      t;
4942dc7a7e3SShri Abhyankar   Vec            U;
4952dc7a7e3SShri Abhyankar   PetscInt       i;
496ea3dac1cSHong Zhang   PetscReal      dt,dt_min,dt_reset = 0.0;
4972dc7a7e3SShri Abhyankar 
4982dc7a7e3SShri Abhyankar   PetscFunctionBegin;
4996427ac75SLisandro Dalcin   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
5006427ac75SLisandro Dalcin   if (!ts->event) PetscFunctionReturn(0);
5016427ac75SLisandro Dalcin   event = ts->event;
5022dc7a7e3SShri Abhyankar 
5032dc7a7e3SShri Abhyankar   ierr = TSGetTime(ts,&t);CHKERRQ(ierr);
5047dbe0728SLisandro Dalcin   ierr = TSGetTimeStep(ts,&dt);CHKERRQ(ierr);
5052dc7a7e3SShri Abhyankar   ierr = TSGetSolution(ts,&U);CHKERRQ(ierr);
5062dc7a7e3SShri Abhyankar 
5077dbe0728SLisandro Dalcin   if (event->status == TSEVENT_NONE) {
5087dbe0728SLisandro Dalcin     event->timestep_prev = dt;
509d294eb03SHong Zhang     event->ptime_end = t;
5107dbe0728SLisandro Dalcin   }
5112dc7a7e3SShri Abhyankar   if (event->status == TSEVENT_RESET_NEXTSTEP) {
512d294eb03SHong Zhang     /* user has specified a PostEventInterval dt */
513458122a4SShri Abhyankar     dt = event->timestep_posteventinterval;
514e97c63d7SStefano Zampini     if (ts->exact_final_time == TS_EXACTFINALTIME_MATCHSTEP) {
515e97c63d7SStefano Zampini       PetscReal maxdt = ts->max_time-t;
516e97c63d7SStefano Zampini       dt = dt > maxdt ? maxdt : (PetscIsCloseAtTol(dt,maxdt,10*PETSC_MACHINE_EPSILON,0) ? maxdt : dt);
517e97c63d7SStefano Zampini     }
5187dbe0728SLisandro Dalcin     ierr = TSSetTimeStep(ts,dt);CHKERRQ(ierr);
5192dc7a7e3SShri Abhyankar     event->status = TSEVENT_NONE;
5202dc7a7e3SShri Abhyankar   }
5212dc7a7e3SShri Abhyankar 
5228860a134SJunchao Zhang   ierr = VecLockReadPush(U);CHKERRQ(ierr);
5236427ac75SLisandro Dalcin   ierr = (*event->eventhandler)(ts,t,U,event->fvalue,event->ctx);CHKERRQ(ierr);
5248860a134SJunchao Zhang   ierr = VecLockReadPop(U);CHKERRQ(ierr);
5259e12be75SShri Abhyankar 
526d294eb03SHong Zhang   /* Detect the events */
527d294eb03SHong Zhang   ierr = TSEventDetection(ts);CHKERRQ(ierr);
528d294eb03SHong Zhang 
529d294eb03SHong Zhang   /* Locate the events */
530d294eb03SHong Zhang   if (event->status == TSEVENT_LOCATED_INTERVAL || event->status == TSEVENT_PROCESSING) {
531d294eb03SHong Zhang     /* Approach the zero crosing by setting a new step size */
532d294eb03SHong Zhang     ierr = TSEventLocation(ts,&dt);CHKERRQ(ierr);
533d294eb03SHong Zhang     /* Roll back when new events are detected */
534d294eb03SHong Zhang     if (event->status == TSEVENT_LOCATED_INTERVAL) {
535d294eb03SHong Zhang       ierr = TSRollBack(ts);CHKERRQ(ierr);
536d294eb03SHong Zhang       ierr = TSSetConvergedReason(ts,TS_CONVERGED_ITERATING);CHKERRQ(ierr);
537d294eb03SHong Zhang       event->iterctr++;
538006e6a18SShri Abhyankar     }
539820f2d46SBarry Smith     ierr = MPIU_Allreduce(&dt,&dt_min,1,MPIU_REAL,MPIU_MIN,PetscObjectComm((PetscObject)ts));CHKERRMPI(ierr);
540ea3dac1cSHong Zhang     if (dt_reset > 0.0 && dt_reset < dt_min) dt_min = dt_reset;
541d294eb03SHong Zhang     ierr = TSSetTimeStep(ts,dt_min);CHKERRQ(ierr);
542d294eb03SHong Zhang     /* Found the zero crossing */
5439e12be75SShri Abhyankar     if (event->status == TSEVENT_ZERO) {
5444597913aSLisandro Dalcin       ierr = TSPostEvent(ts,t,U);CHKERRQ(ierr);
5459e12be75SShri Abhyankar 
546e2cdd850SShri Abhyankar       dt = event->ptime_end - t;
547ad508104SStefano Zampini       if (PetscAbsReal(dt) < PETSC_SMALL) { /* we hit the event, continue with the candidate time step */
548ad508104SStefano Zampini         dt = event->timestep_prev;
549ad508104SStefano Zampini         event->status = TSEVENT_NONE;
550ad508104SStefano Zampini       }
551d294eb03SHong Zhang       if (event->timestep_postevent) { /* user has specified a PostEvent dt*/
552d294eb03SHong Zhang         dt = event->timestep_postevent;
553d294eb03SHong Zhang       }
554e97c63d7SStefano Zampini       if (ts->exact_final_time == TS_EXACTFINALTIME_MATCHSTEP) {
555e97c63d7SStefano Zampini         PetscReal maxdt = ts->max_time-t;
556e97c63d7SStefano Zampini         dt = dt > maxdt ? maxdt : (PetscIsCloseAtTol(dt,maxdt,10*PETSC_MACHINE_EPSILON,0) ? maxdt : dt);
557e97c63d7SStefano Zampini       }
5589e12be75SShri Abhyankar       ierr = TSSetTimeStep(ts,dt);CHKERRQ(ierr);
55938bf2713SShri Abhyankar       event->iterctr = 0;
5609e12be75SShri Abhyankar     }
561d294eb03SHong Zhang     /* Have not found the zero crosing yet */
562d294eb03SHong Zhang     if (event->status == TSEVENT_PROCESSING) {
563d294eb03SHong Zhang       if (event->monitor) {
564d294eb03SHong Zhang         ierr = PetscViewerASCIIPrintf(event->monitor,"TSEvent: iter %D - Stepping forward as no event detected in interval [%g - %g]\n",event->iterctr,(double)event->ptime_prev,(double)t);CHKERRQ(ierr);
565d294eb03SHong Zhang       }
566d294eb03SHong Zhang       event->iterctr++;
567d294eb03SHong Zhang     }
568d294eb03SHong Zhang   }
569d294eb03SHong Zhang   if (event->status == TSEVENT_LOCATED_INTERVAL) { /* The step has been rolled back */
5702dc7a7e3SShri Abhyankar     event->status = TSEVENT_PROCESSING;
571e2cdd850SShri Abhyankar     event->ptime_right = t;
5722dc7a7e3SShri Abhyankar   } else {
573d294eb03SHong Zhang     for (i=0; i < event->nevents; i++) event->fvalue_prev[i] = event->fvalue[i];
57438bf2713SShri Abhyankar     event->ptime_prev = t;
57538bf2713SShri Abhyankar   }
5762dc7a7e3SShri Abhyankar   PetscFunctionReturn(0);
5772dc7a7e3SShri Abhyankar }
5782dc7a7e3SShri Abhyankar 
5796427ac75SLisandro Dalcin PetscErrorCode TSAdjointEventHandler(TS ts)
580d0578d90SShri Abhyankar {
581d0578d90SShri Abhyankar   PetscErrorCode ierr;
5826427ac75SLisandro Dalcin   TSEvent        event;
583d0578d90SShri Abhyankar   PetscReal      t;
584d0578d90SShri Abhyankar   Vec            U;
585d0578d90SShri Abhyankar   PetscInt       ctr;
586d0578d90SShri Abhyankar   PetscBool      forwardsolve=PETSC_FALSE; /* Flag indicating that TS is doing an adjoint solve */
587d0578d90SShri Abhyankar 
588d0578d90SShri Abhyankar   PetscFunctionBegin;
5896427ac75SLisandro Dalcin   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
5906427ac75SLisandro Dalcin   if (!ts->event) PetscFunctionReturn(0);
5916427ac75SLisandro Dalcin   event = ts->event;
592d0578d90SShri Abhyankar 
593d0578d90SShri Abhyankar   ierr = TSGetTime(ts,&t);CHKERRQ(ierr);
594d0578d90SShri Abhyankar   ierr = TSGetSolution(ts,&U);CHKERRQ(ierr);
595d0578d90SShri Abhyankar 
596d0578d90SShri Abhyankar   ctr = event->recorder.ctr-1;
597bcbf8bb3SShri Abhyankar   if (ctr >= 0 && PetscAbsReal(t - event->recorder.time[ctr]) < PETSC_SMALL) {
598d0578d90SShri Abhyankar     /* Call the user postevent function */
599d0578d90SShri Abhyankar     if (event->postevent) {
6006427ac75SLisandro Dalcin       ierr = (*event->postevent)(ts,event->recorder.nevents[ctr],event->recorder.eventidx[ctr],t,U,forwardsolve,event->ctx);CHKERRQ(ierr);
601d0578d90SShri Abhyankar       event->recorder.ctr--;
602d0578d90SShri Abhyankar     }
603d0578d90SShri Abhyankar   }
604d0578d90SShri Abhyankar 
605d0578d90SShri Abhyankar   PetscBarrier((PetscObject)ts);
606d0578d90SShri Abhyankar   PetscFunctionReturn(0);
607d0578d90SShri Abhyankar }
6081ea83e56SMiguel 
6091ea83e56SMiguel /*@
6101ea83e56SMiguel   TSGetNumEvents - Get the numbers of events set
6111ea83e56SMiguel 
6121ea83e56SMiguel   Logically Collective
6131ea83e56SMiguel 
614*4165533cSJose E. Roman   Input Parameter:
61599c90e12SSatish Balay . ts - the TS context
6161ea83e56SMiguel 
617*4165533cSJose E. Roman   Output Parameter:
6181ea83e56SMiguel . nevents - number of events
6191ea83e56SMiguel 
6201ea83e56SMiguel   Level: intermediate
6211ea83e56SMiguel 
6221ea83e56SMiguel .seealso: TSSetEventHandler()
6231ea83e56SMiguel 
6241ea83e56SMiguel @*/
6251ea83e56SMiguel PetscErrorCode TSGetNumEvents(TS ts,PetscInt * nevents)
6261ea83e56SMiguel {
6271ea83e56SMiguel   PetscFunctionBegin;
6281ea83e56SMiguel   *nevents = ts->event->nevents;
6291ea83e56SMiguel   PetscFunctionReturn(0);
6301ea83e56SMiguel }
631