xref: /petsc/src/ts/event/tsevent.c (revision 580bdb303e1ee3b1222b2042810b4c26340259c6)
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);
29e7069c78SShri   if (--(*event)->refct > 0) {*event = 0; 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 
59458122a4SShri Abhyankar   Input Arguments:
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 
90e3005195SShri Abhyankar    Input Arguments:
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;
1772dc7a7e3SShri Abhyankar   TSEvent        event;
178d94325d3SShri Abhyankar   PetscInt       i;
179006e6a18SShri Abhyankar   PetscBool      flg;
180a6c783d2SShri Abhyankar #if defined PETSC_USE_REAL_SINGLE
181a6c783d2SShri Abhyankar   PetscReal      tol=1e-4;
182a6c783d2SShri Abhyankar #else
183d569cc17SSatish Balay   PetscReal      tol=1e-6;
184a6c783d2SShri Abhyankar #endif
1852dc7a7e3SShri Abhyankar 
1862dc7a7e3SShri Abhyankar   PetscFunctionBegin;
1876427ac75SLisandro Dalcin   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
1880a82b154SShri   if (nevents) {
1896427ac75SLisandro Dalcin     PetscValidIntPointer(direction,2);
1906427ac75SLisandro Dalcin     PetscValidIntPointer(terminate,3);
1910a82b154SShri   }
1926427ac75SLisandro Dalcin 
1936427ac75SLisandro Dalcin   ierr = PetscNewLog(ts,&event);CHKERRQ(ierr);
194854ce69bSBarry Smith   ierr = PetscMalloc1(nevents,&event->fvalue);CHKERRQ(ierr);
195854ce69bSBarry Smith   ierr = PetscMalloc1(nevents,&event->fvalue_prev);CHKERRQ(ierr);
196e2cdd850SShri Abhyankar   ierr = PetscMalloc1(nevents,&event->fvalue_right);CHKERRQ(ierr);
197e2cdd850SShri Abhyankar   ierr = PetscMalloc1(nevents,&event->zerocrossing);CHKERRQ(ierr);
198e2cdd850SShri Abhyankar   ierr = PetscMalloc1(nevents,&event->side);CHKERRQ(ierr);
199854ce69bSBarry Smith   ierr = PetscMalloc1(nevents,&event->direction);CHKERRQ(ierr);
200854ce69bSBarry Smith   ierr = PetscMalloc1(nevents,&event->terminate);CHKERRQ(ierr);
201e3005195SShri Abhyankar   ierr = PetscMalloc1(nevents,&event->vtol);CHKERRQ(ierr);
202d94325d3SShri Abhyankar   for (i=0; i < nevents; i++) {
203d94325d3SShri Abhyankar     event->direction[i] = direction[i];
204d94325d3SShri Abhyankar     event->terminate[i] = terminate[i];
205e2cdd850SShri Abhyankar     event->zerocrossing[i] = PETSC_FALSE;
206e2cdd850SShri Abhyankar     event->side[i] = 0;
207d94325d3SShri Abhyankar   }
208854ce69bSBarry Smith   ierr = PetscMalloc1(nevents,&event->events_zero);CHKERRQ(ierr);
2092589fa24SLisandro Dalcin   event->nevents = nevents;
2106427ac75SLisandro Dalcin   event->eventhandler = eventhandler;
2112dc7a7e3SShri Abhyankar   event->postevent = postevent;
2126427ac75SLisandro Dalcin   event->ctx = ctx;
213458122a4SShri Abhyankar   event->timestep_posteventinterval = ts->time_step;
2142dc7a7e3SShri Abhyankar 
21502749585SLisandro Dalcin   event->recsize = 8;  /* Initial size of the recorder */
2165fbebc36SLisandro Dalcin   ierr = PetscOptionsBegin(((PetscObject)ts)->comm,((PetscObject)ts)->prefix,"TS Event options","TS");CHKERRQ(ierr);
2172dc7a7e3SShri Abhyankar   {
21802749585SLisandro Dalcin     ierr = PetscOptionsReal("-ts_event_tol","Scalar event tolerance for zero crossing check","TSSetEventTolerances",tol,&tol,NULL);CHKERRQ(ierr);
219006e6a18SShri Abhyankar     ierr = PetscOptionsName("-ts_event_monitor","Print choices made by event handler","",&flg);CHKERRQ(ierr);
220a4ffd976SShri Abhyankar     ierr = PetscOptionsInt("-ts_event_recorder_initial_size","Initial size of event recorder","",event->recsize,&event->recsize,NULL);CHKERRQ(ierr);
221458122a4SShri Abhyankar     ierr = PetscOptionsReal("-ts_event_post_eventinterval_step","Time step after event interval","",event->timestep_posteventinterval,&event->timestep_posteventinterval,NULL);CHKERRQ(ierr);
2222dc7a7e3SShri Abhyankar   }
223b6518c14SStefano Zampini   ierr = PetscOptionsEnd();CHKERRQ(ierr);
224a4ffd976SShri Abhyankar 
225a4ffd976SShri Abhyankar   ierr = PetscMalloc1(event->recsize,&event->recorder.time);CHKERRQ(ierr);
226a4ffd976SShri Abhyankar   ierr = PetscMalloc1(event->recsize,&event->recorder.stepnum);CHKERRQ(ierr);
227a4ffd976SShri Abhyankar   ierr = PetscMalloc1(event->recsize,&event->recorder.nevents);CHKERRQ(ierr);
228a4ffd976SShri Abhyankar   ierr = PetscMalloc1(event->recsize,&event->recorder.eventidx);CHKERRQ(ierr);
229a4ffd976SShri Abhyankar   for (i=0; i < event->recsize; i++) {
230a4ffd976SShri Abhyankar     ierr = PetscMalloc1(event->nevents,&event->recorder.eventidx[i]);CHKERRQ(ierr);
231a4ffd976SShri Abhyankar   }
232e7069c78SShri   /* Initialize the event recorder */
233e7069c78SShri   event->recorder.ctr = 0;
234a4ffd976SShri Abhyankar 
235e3005195SShri Abhyankar   for (i=0; i < event->nevents; i++) event->vtol[i] = tol;
2366427ac75SLisandro Dalcin   if (flg) {ierr = PetscViewerASCIIOpen(PETSC_COMM_SELF,"stdout",&event->monitor);CHKERRQ(ierr);}
2379e12be75SShri Abhyankar 
2386427ac75SLisandro Dalcin   ierr = TSEventDestroy(&ts->event);CHKERRQ(ierr);
239d94325d3SShri Abhyankar   ts->event = event;
240e7069c78SShri   ts->event->refct = 1;
2412dc7a7e3SShri Abhyankar   PetscFunctionReturn(0);
2422dc7a7e3SShri Abhyankar }
2432dc7a7e3SShri Abhyankar 
244a4ffd976SShri Abhyankar /*
245a4ffd976SShri Abhyankar   TSEventRecorderResize - Resizes (2X) the event recorder arrays whenever the recording limit (event->recsize)
246a4ffd976SShri Abhyankar                           is reached.
247a4ffd976SShri Abhyankar */
24802749585SLisandro Dalcin static PetscErrorCode TSEventRecorderResize(TSEvent event)
249a4ffd976SShri Abhyankar {
250a4ffd976SShri Abhyankar   PetscErrorCode ierr;
251a4ffd976SShri Abhyankar   PetscReal      *time;
252a4ffd976SShri Abhyankar   PetscInt       *stepnum;
253a4ffd976SShri Abhyankar   PetscInt       *nevents;
254a4ffd976SShri Abhyankar   PetscInt       **eventidx;
255a4ffd976SShri Abhyankar   PetscInt       i,fact=2;
256a4ffd976SShri Abhyankar 
257a4ffd976SShri Abhyankar   PetscFunctionBegin;
258a4ffd976SShri Abhyankar 
259a4ffd976SShri Abhyankar   /* Create large arrays */
260a4ffd976SShri Abhyankar   ierr = PetscMalloc1(fact*event->recsize,&time);CHKERRQ(ierr);
261a4ffd976SShri Abhyankar   ierr = PetscMalloc1(fact*event->recsize,&stepnum);CHKERRQ(ierr);
262a4ffd976SShri Abhyankar   ierr = PetscMalloc1(fact*event->recsize,&nevents);CHKERRQ(ierr);
263a4ffd976SShri Abhyankar   ierr = PetscMalloc1(fact*event->recsize,&eventidx);CHKERRQ(ierr);
264a4ffd976SShri Abhyankar   for (i=0; i < fact*event->recsize; i++) {
265a4ffd976SShri Abhyankar     ierr = PetscMalloc1(event->nevents,&eventidx[i]);CHKERRQ(ierr);
266a4ffd976SShri Abhyankar   }
267a4ffd976SShri Abhyankar 
268a4ffd976SShri Abhyankar   /* Copy over data */
269*580bdb30SBarry Smith   ierr = PetscArraycpy(time,event->recorder.time,event->recsize);CHKERRQ(ierr);
270*580bdb30SBarry Smith   ierr = PetscArraycpy(stepnum,event->recorder.stepnum,event->recsize);CHKERRQ(ierr);
271*580bdb30SBarry Smith   ierr = PetscArraycpy(nevents,event->recorder.nevents,event->recsize);CHKERRQ(ierr);
272a4ffd976SShri Abhyankar   for (i=0; i < event->recsize; i++) {
273*580bdb30SBarry Smith     ierr = PetscArraycpy(eventidx[i],event->recorder.eventidx[i],event->recorder.nevents[i]);CHKERRQ(ierr);
274a4ffd976SShri Abhyankar   }
275a4ffd976SShri Abhyankar 
276a4ffd976SShri Abhyankar   /* Destroy old arrays */
277a4ffd976SShri Abhyankar   for (i=0; i < event->recsize; i++) {
278a4ffd976SShri Abhyankar     ierr = PetscFree(event->recorder.eventidx[i]);CHKERRQ(ierr);
279a4ffd976SShri Abhyankar   }
280a4ffd976SShri Abhyankar   ierr = PetscFree(event->recorder.eventidx);CHKERRQ(ierr);
281a4ffd976SShri Abhyankar   ierr = PetscFree(event->recorder.nevents);CHKERRQ(ierr);
282a4ffd976SShri Abhyankar   ierr = PetscFree(event->recorder.stepnum);CHKERRQ(ierr);
283a4ffd976SShri Abhyankar   ierr = PetscFree(event->recorder.time);CHKERRQ(ierr);
284a4ffd976SShri Abhyankar 
285a4ffd976SShri Abhyankar   /* Set pointers */
286a4ffd976SShri Abhyankar   event->recorder.time = time;
287a4ffd976SShri Abhyankar   event->recorder.stepnum = stepnum;
288a4ffd976SShri Abhyankar   event->recorder.nevents = nevents;
289a4ffd976SShri Abhyankar   event->recorder.eventidx = eventidx;
290a4ffd976SShri Abhyankar 
291a4ffd976SShri Abhyankar   /* Double size */
292a4ffd976SShri Abhyankar   event->recsize *= fact;
293a4ffd976SShri Abhyankar 
294a4ffd976SShri Abhyankar   PetscFunctionReturn(0);
295a4ffd976SShri Abhyankar }
296a4ffd976SShri Abhyankar 
297031fbad4SShri Abhyankar /*
298ac6a796dSBarry Smith    Helper routine to handle user postevents and recording
299031fbad4SShri Abhyankar */
3004597913aSLisandro Dalcin static PetscErrorCode TSPostEvent(TS ts,PetscReal t,Vec U)
3012dc7a7e3SShri Abhyankar {
3022dc7a7e3SShri Abhyankar   PetscErrorCode ierr;
3032dc7a7e3SShri Abhyankar   TSEvent        event = ts->event;
3042dc7a7e3SShri Abhyankar   PetscBool      terminate = PETSC_FALSE;
30528d5b5d6SLisandro Dalcin   PetscBool      restart = PETSC_FALSE;
306d0578d90SShri Abhyankar   PetscInt       i,ctr,stepnum;
3077324a0ffSLisandro Dalcin   PetscBool      inflag[2],outflag[2];
3084597913aSLisandro Dalcin   PetscBool      forwardsolve = PETSC_TRUE; /* Flag indicating that TS is doing a forward solve */
3092dc7a7e3SShri Abhyankar 
3102dc7a7e3SShri Abhyankar   PetscFunctionBegin;
3112dc7a7e3SShri Abhyankar   if (event->postevent) {
31228d5b5d6SLisandro Dalcin     PetscObjectState state_prev,state_post;
31328d5b5d6SLisandro Dalcin     ierr = PetscObjectStateGet((PetscObject)U,&state_prev);CHKERRQ(ierr);
3144597913aSLisandro Dalcin     ierr = (*event->postevent)(ts,event->nevents_zero,event->events_zero,t,U,forwardsolve,event->ctx);CHKERRQ(ierr);
31528d5b5d6SLisandro Dalcin     ierr = PetscObjectStateGet((PetscObject)U,&state_post);CHKERRQ(ierr);
31628d5b5d6SLisandro Dalcin     if (state_prev != state_post) restart = PETSC_TRUE;
3172dc7a7e3SShri Abhyankar   }
3184597913aSLisandro Dalcin 
31928d5b5d6SLisandro Dalcin   /* Handle termination events and step restart */
32028d5b5d6SLisandro Dalcin   for (i=0; i<event->nevents_zero; i++) if (event->terminate[event->events_zero[i]]) terminate = PETSC_TRUE;
3217324a0ffSLisandro Dalcin   inflag[0] = restart; inflag[1] = terminate;
3227324a0ffSLisandro Dalcin   ierr = MPIU_Allreduce(inflag,outflag,2,MPIU_BOOL,MPI_LOR,((PetscObject)ts)->comm);CHKERRQ(ierr);
3237324a0ffSLisandro Dalcin   restart = outflag[0]; terminate = outflag[1];
3247324a0ffSLisandro Dalcin   if (restart) {ierr = TSRestartStep(ts);CHKERRQ(ierr);}
3257324a0ffSLisandro Dalcin   if (terminate) {ierr = TSSetConvergedReason(ts,TS_CONVERGED_EVENT);CHKERRQ(ierr);}
3267324a0ffSLisandro Dalcin   event->status = terminate ? TSEVENT_NONE : TSEVENT_RESET_NEXTSTEP;
327f7aea88cSShri Abhyankar 
3284597913aSLisandro Dalcin   /* Reset event residual functions as states might get changed by the postevent callback */
329f443add6SLisandro Dalcin   if (event->postevent) {
3308860a134SJunchao Zhang     ierr = VecLockReadPush(U);CHKERRQ(ierr);
331f443add6SLisandro Dalcin     ierr = (*event->eventhandler)(ts,t,U,event->fvalue,event->ctx);CHKERRQ(ierr);
3328860a134SJunchao Zhang     ierr = VecLockReadPop(U);CHKERRQ(ierr);
333f443add6SLisandro Dalcin   }
334f443add6SLisandro Dalcin 
335f443add6SLisandro Dalcin   /* Cache current time and event residual functions */
336f443add6SLisandro Dalcin   event->ptime_prev = t;
337f443add6SLisandro Dalcin   for (i=0; i<event->nevents; i++)
338f443add6SLisandro Dalcin     event->fvalue_prev[i] = event->fvalue[i];
3394597913aSLisandro Dalcin 
340d0578d90SShri Abhyankar   /* Record the event in the event recorder */
34180275a0aSLisandro Dalcin   ierr = TSGetStepNumber(ts,&stepnum);CHKERRQ(ierr);
342f7aea88cSShri Abhyankar   ctr = event->recorder.ctr;
343a4ffd976SShri Abhyankar   if (ctr == event->recsize) {
344a4ffd976SShri Abhyankar     ierr = TSEventRecorderResize(event);CHKERRQ(ierr);
345a4ffd976SShri Abhyankar   }
346f7aea88cSShri Abhyankar   event->recorder.time[ctr] = t;
347d0578d90SShri Abhyankar   event->recorder.stepnum[ctr] = stepnum;
3484597913aSLisandro Dalcin   event->recorder.nevents[ctr] = event->nevents_zero;
3494597913aSLisandro Dalcin   for (i=0; i<event->nevents_zero; i++) event->recorder.eventidx[ctr][i] = event->events_zero[i];
350f7aea88cSShri Abhyankar   event->recorder.ctr++;
3512dc7a7e3SShri Abhyankar   PetscFunctionReturn(0);
3522dc7a7e3SShri Abhyankar }
3532dc7a7e3SShri Abhyankar 
35402749585SLisandro Dalcin /* Uses Anderson-Bjorck variant of regula falsi method */
355a3a8645aSShri Abhyankar PETSC_STATIC_INLINE PetscReal TSEventComputeStepSize(PetscReal tleft,PetscReal t,PetscReal tright,PetscScalar fleft,PetscScalar f,PetscScalar fright,PetscInt side,PetscReal dt)
35638bf2713SShri Abhyankar {
35702749585SLisandro Dalcin   PetscReal new_dt, scal = 1.0;
358e2cdd850SShri Abhyankar   if (PetscRealPart(fleft)*PetscRealPart(f) < 0) {
359e2cdd850SShri Abhyankar     if (side == 1) {
360a6c783d2SShri Abhyankar       scal = (PetscRealPart(fright) - PetscRealPart(f))/PetscRealPart(fright);
361a6c783d2SShri Abhyankar       if (scal < PETSC_SMALL) scal = 0.5;
362e2cdd850SShri Abhyankar     }
36302749585SLisandro Dalcin     new_dt = (scal*PetscRealPart(fleft)*t - PetscRealPart(f)*tleft)/(scal*PetscRealPart(fleft) - PetscRealPart(f)) - tleft;
364e2cdd850SShri Abhyankar   } else {
365e2cdd850SShri Abhyankar     if (side == -1) {
366a6c783d2SShri Abhyankar       scal = (PetscRealPart(fleft) - PetscRealPart(f))/PetscRealPart(fleft);
367a6c783d2SShri Abhyankar       if (scal < PETSC_SMALL) scal = 0.5;
368e2cdd850SShri Abhyankar     }
36902749585SLisandro Dalcin     new_dt = (PetscRealPart(f)*tright - scal*PetscRealPart(fright)*t)/(PetscRealPart(f) - scal*PetscRealPart(fright)) - t;
370e2cdd850SShri Abhyankar   }
37102749585SLisandro Dalcin   return PetscMin(dt,new_dt);
37238bf2713SShri Abhyankar }
373e2cdd850SShri Abhyankar 
37438bf2713SShri Abhyankar 
3756427ac75SLisandro Dalcin PetscErrorCode TSEventHandler(TS ts)
3762dc7a7e3SShri Abhyankar {
3772dc7a7e3SShri Abhyankar   PetscErrorCode ierr;
3786427ac75SLisandro Dalcin   TSEvent        event;
3792dc7a7e3SShri Abhyankar   PetscReal      t;
3802dc7a7e3SShri Abhyankar   Vec            U;
3812dc7a7e3SShri Abhyankar   PetscInt       i;
3827dbe0728SLisandro Dalcin   PetscReal      dt,dt_min;
3832dc7a7e3SShri Abhyankar   PetscInt       rollback=0,in[2],out[2];
3849e12be75SShri Abhyankar   PetscInt       fvalue_sign,fvalueprev_sign;
3852dc7a7e3SShri Abhyankar 
3862dc7a7e3SShri Abhyankar   PetscFunctionBegin;
3876427ac75SLisandro Dalcin   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
3886427ac75SLisandro Dalcin   if (!ts->event) PetscFunctionReturn(0);
3896427ac75SLisandro Dalcin   event = ts->event;
3902dc7a7e3SShri Abhyankar 
3912dc7a7e3SShri Abhyankar   ierr = TSGetTime(ts,&t);CHKERRQ(ierr);
3927dbe0728SLisandro Dalcin   ierr = TSGetTimeStep(ts,&dt);CHKERRQ(ierr);
3932dc7a7e3SShri Abhyankar   ierr = TSGetSolution(ts,&U);CHKERRQ(ierr);
3942dc7a7e3SShri Abhyankar 
3957dbe0728SLisandro Dalcin   if (event->status == TSEVENT_NONE) {
3967dbe0728SLisandro Dalcin     event->timestep_prev = dt;
3977dbe0728SLisandro Dalcin   }
3987dbe0728SLisandro Dalcin 
3992dc7a7e3SShri Abhyankar   if (event->status == TSEVENT_RESET_NEXTSTEP) {
400458122a4SShri Abhyankar     dt = event->timestep_posteventinterval;
4017dbe0728SLisandro Dalcin     ierr = TSSetTimeStep(ts,dt);CHKERRQ(ierr);
4022dc7a7e3SShri Abhyankar     event->status = TSEVENT_NONE;
4032dc7a7e3SShri Abhyankar   }
4042dc7a7e3SShri Abhyankar 
4052dc7a7e3SShri Abhyankar   if (event->status == TSEVENT_NONE) {
4067dbe0728SLisandro Dalcin     event->ptime_end = t;
4072dc7a7e3SShri Abhyankar   }
4082dc7a7e3SShri Abhyankar 
4098860a134SJunchao Zhang   ierr = VecLockReadPush(U);CHKERRQ(ierr);
4106427ac75SLisandro Dalcin   ierr = (*event->eventhandler)(ts,t,U,event->fvalue,event->ctx);CHKERRQ(ierr);
4118860a134SJunchao Zhang   ierr = VecLockReadPop(U);CHKERRQ(ierr);
4129e12be75SShri Abhyankar 
4132dc7a7e3SShri Abhyankar   for (i=0; i < event->nevents; i++) {
414e3005195SShri Abhyankar     if (PetscAbsScalar(event->fvalue[i]) < event->vtol[i]) {
4152dc7a7e3SShri Abhyankar       event->status = TSEVENT_ZERO;
416e2cdd850SShri Abhyankar       event->fvalue_right[i] = event->fvalue[i];
4179e12be75SShri Abhyankar       continue;
418006e6a18SShri Abhyankar     }
419d94325d3SShri Abhyankar     fvalue_sign = PetscSign(PetscRealPart(event->fvalue[i]));
420d94325d3SShri Abhyankar     fvalueprev_sign = PetscSign(PetscRealPart(event->fvalue_prev[i]));
421e3005195SShri Abhyankar     if (fvalueprev_sign != 0 && (fvalue_sign != fvalueprev_sign) && (PetscAbsScalar(event->fvalue_prev[i]) > event->vtol[i])) {
422d94325d3SShri Abhyankar       switch (event->direction[i]) {
423d94325d3SShri Abhyankar       case -1:
424d94325d3SShri Abhyankar         if (fvalue_sign < 0) {
4252dc7a7e3SShri Abhyankar           rollback = 1;
426e2cdd850SShri Abhyankar 
427e2cdd850SShri Abhyankar           /* Compute new time step */
428e2cdd850SShri Abhyankar           dt = TSEventComputeStepSize(event->ptime_prev,t,event->ptime_right,event->fvalue_prev[i],event->fvalue[i],event->fvalue_right[i],event->side[i],dt);
429e2cdd850SShri Abhyankar 
4306427ac75SLisandro Dalcin           if (event->monitor) {
43138bf2713SShri Abhyankar             ierr = PetscViewerASCIIPrintf(event->monitor,"TSEvent: iter %D - Event %D interval detected [%g - %g]\n",event->iterctr,i,(double)event->ptime_prev,(double)t);CHKERRQ(ierr);
432006e6a18SShri Abhyankar           }
433e2cdd850SShri Abhyankar           event->fvalue_right[i] = event->fvalue[i];
434e2cdd850SShri Abhyankar           event->side[i] = 1;
435e2cdd850SShri Abhyankar 
436e2cdd850SShri Abhyankar           if (!event->iterctr) event->zerocrossing[i] = PETSC_TRUE;
437e2cdd850SShri Abhyankar           event->status = TSEVENT_LOCATED_INTERVAL;
4382dc7a7e3SShri Abhyankar         }
439d94325d3SShri Abhyankar         break;
440d94325d3SShri Abhyankar       case 1:
441d94325d3SShri Abhyankar         if (fvalue_sign > 0) {
442d94325d3SShri Abhyankar           rollback = 1;
443e2cdd850SShri Abhyankar 
444e2cdd850SShri Abhyankar           /* Compute new time step */
445e2cdd850SShri Abhyankar           dt = TSEventComputeStepSize(event->ptime_prev,t,event->ptime_right,event->fvalue_prev[i],event->fvalue[i],event->fvalue_right[i],event->side[i],dt);
446e2cdd850SShri Abhyankar 
4476427ac75SLisandro Dalcin           if (event->monitor) {
44838bf2713SShri Abhyankar             ierr = PetscViewerASCIIPrintf(event->monitor,"TSEvent: iter %D - Event %D interval detected [%g - %g]\n",event->iterctr,i,(double)event->ptime_prev,(double)t);CHKERRQ(ierr);
449006e6a18SShri Abhyankar           }
450e2cdd850SShri Abhyankar           event->fvalue_right[i] = event->fvalue[i];
451e2cdd850SShri Abhyankar           event->side[i] = 1;
452e2cdd850SShri Abhyankar 
453e2cdd850SShri Abhyankar           if (!event->iterctr) event->zerocrossing[i] = PETSC_TRUE;
454e2cdd850SShri Abhyankar           event->status = TSEVENT_LOCATED_INTERVAL;
4552dc7a7e3SShri Abhyankar         }
456d94325d3SShri Abhyankar         break;
457d94325d3SShri Abhyankar       case 0:
458d94325d3SShri Abhyankar         rollback = 1;
459e2cdd850SShri Abhyankar 
460e2cdd850SShri Abhyankar         /* Compute new time step */
461e2cdd850SShri Abhyankar         dt = TSEventComputeStepSize(event->ptime_prev,t,event->ptime_right,event->fvalue_prev[i],event->fvalue[i],event->fvalue_right[i],event->side[i],dt);
462e2cdd850SShri Abhyankar 
4636427ac75SLisandro Dalcin         if (event->monitor) {
46438bf2713SShri Abhyankar           ierr = PetscViewerASCIIPrintf(event->monitor,"TSEvent: iter %D - Event %D interval detected [%g - %g]\n",event->iterctr,i,(double)event->ptime_prev,(double)t);CHKERRQ(ierr);
465006e6a18SShri Abhyankar         }
466e2cdd850SShri Abhyankar         event->fvalue_right[i] = event->fvalue[i];
467e2cdd850SShri Abhyankar         event->side[i] = 1;
468e2cdd850SShri Abhyankar 
469e2cdd850SShri Abhyankar         if (!event->iterctr) event->zerocrossing[i] = PETSC_TRUE;
470e2cdd850SShri Abhyankar         event->status = TSEVENT_LOCATED_INTERVAL;
471e2cdd850SShri Abhyankar 
472d94325d3SShri Abhyankar         break;
473d94325d3SShri Abhyankar       }
474d94325d3SShri Abhyankar     }
475d94325d3SShri Abhyankar   }
4767dbe0728SLisandro Dalcin 
4772589fa24SLisandro Dalcin   in[0] = event->status; in[1] = rollback;
4787dbe0728SLisandro Dalcin   ierr = MPIU_Allreduce(in,out,2,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)ts));CHKERRQ(ierr);
4792589fa24SLisandro Dalcin   event->status = (TSEventStatus)out[0]; rollback = out[1];
4802589fa24SLisandro Dalcin   if (rollback) event->status = TSEVENT_LOCATED_INTERVAL;
4812dc7a7e3SShri Abhyankar 
4827dbe0728SLisandro Dalcin   event->nevents_zero = 0;
4839e12be75SShri Abhyankar   if (event->status == TSEVENT_ZERO) {
4849e12be75SShri Abhyankar     for (i=0; i < event->nevents; i++) {
4859e12be75SShri Abhyankar       if (PetscAbsScalar(event->fvalue[i]) < event->vtol[i]) {
4869e12be75SShri Abhyankar         event->events_zero[event->nevents_zero++] = i;
4876427ac75SLisandro Dalcin         if (event->monitor) {
48838bf2713SShri Abhyankar           ierr = PetscViewerASCIIPrintf(event->monitor,"TSEvent: Event %D zero crossing at time %g located in %D iterations\n",i,(double)t,event->iterctr);CHKERRQ(ierr);
4899e12be75SShri Abhyankar         }
490e2cdd850SShri Abhyankar         event->zerocrossing[i] = PETSC_FALSE;
4919e12be75SShri Abhyankar       }
492e2cdd850SShri Abhyankar       event->side[i] = 0;
4939e12be75SShri Abhyankar     }
4944597913aSLisandro Dalcin     ierr = TSPostEvent(ts,t,U);CHKERRQ(ierr);
4959e12be75SShri Abhyankar 
496e2cdd850SShri Abhyankar     dt = event->ptime_end - t;
497ad508104SStefano Zampini     if (PetscAbsReal(dt) < PETSC_SMALL) { /* we hit the event, continue with the candidate time step */
498ad508104SStefano Zampini       dt = event->timestep_prev;
499ad508104SStefano Zampini       event->status = TSEVENT_NONE;
500ad508104SStefano Zampini     }
5019e12be75SShri Abhyankar     ierr = TSSetTimeStep(ts,dt);CHKERRQ(ierr);
50238bf2713SShri Abhyankar     event->iterctr = 0;
5039e12be75SShri Abhyankar     PetscFunctionReturn(0);
5049e12be75SShri Abhyankar   }
5059e12be75SShri Abhyankar 
5062dc7a7e3SShri Abhyankar   if (event->status == TSEVENT_LOCATED_INTERVAL) {
5072dc7a7e3SShri Abhyankar     ierr = TSRollBack(ts);CHKERRQ(ierr);
5082589fa24SLisandro Dalcin     ierr = TSSetConvergedReason(ts,TS_CONVERGED_ITERATING);CHKERRQ(ierr);
5092dc7a7e3SShri Abhyankar     event->status = TSEVENT_PROCESSING;
510e2cdd850SShri Abhyankar     event->ptime_right = t;
5112dc7a7e3SShri Abhyankar   } else {
5122dc7a7e3SShri Abhyankar     for (i=0; i < event->nevents; i++) {
513e2cdd850SShri Abhyankar       if (event->status == TSEVENT_PROCESSING && event->zerocrossing[i]) {
514e2cdd850SShri Abhyankar         /* Compute new time step */
515e2cdd850SShri Abhyankar         dt = TSEventComputeStepSize(event->ptime_prev,t,event->ptime_right,event->fvalue_prev[i],event->fvalue[i],event->fvalue_right[i],event->side[i],dt);
516e2cdd850SShri Abhyankar         event->side[i] = -1;
517e2cdd850SShri Abhyankar       }
5182dc7a7e3SShri Abhyankar       event->fvalue_prev[i] = event->fvalue[i];
5192dc7a7e3SShri Abhyankar     }
520e2cdd850SShri Abhyankar     if (event->monitor && event->status == TSEVENT_PROCESSING) {
52138bf2713SShri Abhyankar       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);
5222dc7a7e3SShri Abhyankar     }
52338bf2713SShri Abhyankar     event->ptime_prev = t;
52438bf2713SShri Abhyankar   }
52538bf2713SShri Abhyankar 
52638bf2713SShri Abhyankar   if (event->status == TSEVENT_PROCESSING) event->iterctr++;
5279e12be75SShri Abhyankar 
5287dbe0728SLisandro Dalcin   ierr = MPIU_Allreduce(&dt,&dt_min,1,MPIU_REAL,MPIU_MIN,PetscObjectComm((PetscObject)ts));CHKERRQ(ierr);
5297dbe0728SLisandro Dalcin   ierr = TSSetTimeStep(ts,dt_min);CHKERRQ(ierr);
5302dc7a7e3SShri Abhyankar   PetscFunctionReturn(0);
5312dc7a7e3SShri Abhyankar }
5322dc7a7e3SShri Abhyankar 
5336427ac75SLisandro Dalcin PetscErrorCode TSAdjointEventHandler(TS ts)
534d0578d90SShri Abhyankar {
535d0578d90SShri Abhyankar   PetscErrorCode ierr;
5366427ac75SLisandro Dalcin   TSEvent        event;
537d0578d90SShri Abhyankar   PetscReal      t;
538d0578d90SShri Abhyankar   Vec            U;
539d0578d90SShri Abhyankar   PetscInt       ctr;
540d0578d90SShri Abhyankar   PetscBool      forwardsolve=PETSC_FALSE; /* Flag indicating that TS is doing an adjoint solve */
541d0578d90SShri Abhyankar 
542d0578d90SShri Abhyankar   PetscFunctionBegin;
5436427ac75SLisandro Dalcin   PetscValidHeaderSpecific(ts,TS_CLASSID,1);
5446427ac75SLisandro Dalcin   if (!ts->event) PetscFunctionReturn(0);
5456427ac75SLisandro Dalcin   event = ts->event;
546d0578d90SShri Abhyankar 
547d0578d90SShri Abhyankar   ierr = TSGetTime(ts,&t);CHKERRQ(ierr);
548d0578d90SShri Abhyankar   ierr = TSGetSolution(ts,&U);CHKERRQ(ierr);
549d0578d90SShri Abhyankar 
550d0578d90SShri Abhyankar   ctr = event->recorder.ctr-1;
551bcbf8bb3SShri Abhyankar   if (ctr >= 0 && PetscAbsReal(t - event->recorder.time[ctr]) < PETSC_SMALL) {
552d0578d90SShri Abhyankar     /* Call the user postevent function */
553d0578d90SShri Abhyankar     if (event->postevent) {
5546427ac75SLisandro Dalcin       ierr = (*event->postevent)(ts,event->recorder.nevents[ctr],event->recorder.eventidx[ctr],t,U,forwardsolve,event->ctx);CHKERRQ(ierr);
555d0578d90SShri Abhyankar       event->recorder.ctr--;
556d0578d90SShri Abhyankar     }
557d0578d90SShri Abhyankar   }
558d0578d90SShri Abhyankar 
559d0578d90SShri Abhyankar   PetscBarrier((PetscObject)ts);
560d0578d90SShri Abhyankar   PetscFunctionReturn(0);
561d0578d90SShri Abhyankar }
562