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