xref: /petsc/src/ts/event/tsevent.c (revision 2dc7a7e3be1fcbc385870e5e5517280010d83adf)
1*2dc7a7e3SShri Abhyankar 
2*2dc7a7e3SShri Abhyankar #include <petsc-private/tsimpl.h> /*I  "petscts.h" I*/
3*2dc7a7e3SShri Abhyankar 
4*2dc7a7e3SShri Abhyankar #undef __FUNCT__
5*2dc7a7e3SShri Abhyankar #define __FUNCT__ "TSSetEventMonitor"
6*2dc7a7e3SShri Abhyankar /*@C
7*2dc7a7e3SShri Abhyankar    TSSetEventMonitor - Sets a monitoring function used for detecting events
8*2dc7a7e3SShri Abhyankar 
9*2dc7a7e3SShri Abhyankar    Logically Collective on TS
10*2dc7a7e3SShri Abhyankar 
11*2dc7a7e3SShri Abhyankar    Input Parameters:
12*2dc7a7e3SShri Abhyankar +  ts - the TS context obtained from TSCreate()
13*2dc7a7e3SShri Abhyankar .  nevents - number of local events
14*2dc7a7e3SShri Abhyankar .  eventmonitor - event monitoring routine
15*2dc7a7e3SShri Abhyankar .  postevent - [optional] post-event function
16*2dc7a7e3SShri Abhyankar -  mectx - [optional] user-defined context for private data for the
17*2dc7a7e3SShri Abhyankar               event monitor and post event routine (use NULL if no
18*2dc7a7e3SShri Abhyankar               context is desired)
19*2dc7a7e3SShri Abhyankar 
20*2dc7a7e3SShri Abhyankar    Calling sequence of eventmonitor:
21*2dc7a7e3SShri Abhyankar    PetscErrorCode EventMonitor(TS ts,PetscReal t,Vec U,PetscScalar *fvalue,PetscInt *direction,PetscBool *terminate,void* mectx)
22*2dc7a7e3SShri Abhyankar 
23*2dc7a7e3SShri Abhyankar    Input Parameters:
24*2dc7a7e3SShri Abhyankar +  ts  - the TS context
25*2dc7a7e3SShri Abhyankar .  t   - current time
26*2dc7a7e3SShri Abhyankar .  U   - current iterate
27*2dc7a7e3SShri Abhyankar -  ctx - [optional] context passed with eventmonitor
28*2dc7a7e3SShri Abhyankar 
29*2dc7a7e3SShri Abhyankar    Output parameters:
30*2dc7a7e3SShri Abhyankar +  fvalue    - function value of events at time t
31*2dc7a7e3SShri Abhyankar .  direction - direction of zero crossing to be detected. -1 => Zero crossing in negative direction,
32*2dc7a7e3SShri Abhyankar                +1 => Zero crossing in positive direction, 0 => both ways
33*2dc7a7e3SShri Abhyankar -  terminate - terminate time stepping after event is detected.
34*2dc7a7e3SShri Abhyankar 
35*2dc7a7e3SShri Abhyankar    Calling sequence of postevent:
36*2dc7a7e3SShri Abhyankar    PetscErrorCode PostEvent(TS ts,PetscInt nevents_zero, PetscInt events_zero, PetscReal t,Vec U,void* ctx)
37*2dc7a7e3SShri Abhyankar 
38*2dc7a7e3SShri Abhyankar    Input Parameters:
39*2dc7a7e3SShri Abhyankar +  ts - the TS context
40*2dc7a7e3SShri Abhyankar .  nevents_zero - number of local events whose event function is zero
41*2dc7a7e3SShri Abhyankar .  events_zero  - indices of local events which have reached zero
42*2dc7a7e3SShri Abhyankar .  t            - current time
43*2dc7a7e3SShri Abhyankar .  U            - current solution
44*2dc7a7e3SShri Abhyankar -  ctx          - the context passed with eventmonitor
45*2dc7a7e3SShri Abhyankar 
46*2dc7a7e3SShri Abhyankar    Level: intermediate
47*2dc7a7e3SShri Abhyankar 
48*2dc7a7e3SShri Abhyankar .keywords: TS, event, set, monitor
49*2dc7a7e3SShri Abhyankar 
50*2dc7a7e3SShri Abhyankar .seealso: TSCreate(), TSSetTimeStep(), TSSetConvergedReason()
51*2dc7a7e3SShri Abhyankar @*/
52*2dc7a7e3SShri Abhyankar PetscErrorCode TSSetEventMonitor(TS ts,PetscInt nevents,PetscErrorCode (*eventmonitor)(TS,PetscReal,Vec,PetscScalar*,PetscInt*,PetscBool*,void*),PetscErrorCode (*postevent)(TS,PetscInt,PetscInt[],PetscReal,Vec,void*),void *mectx)
53*2dc7a7e3SShri Abhyankar {
54*2dc7a7e3SShri Abhyankar   PetscErrorCode ierr;
55*2dc7a7e3SShri Abhyankar   PetscReal      t;
56*2dc7a7e3SShri Abhyankar   Vec            U;
57*2dc7a7e3SShri Abhyankar   TSEvent        event;
58*2dc7a7e3SShri Abhyankar 
59*2dc7a7e3SShri Abhyankar   PetscFunctionBegin;
60*2dc7a7e3SShri Abhyankar   ierr = PetscNew(struct _p_TSEvent,&ts->event);CHKERRQ(ierr);
61*2dc7a7e3SShri Abhyankar   event = ts->event;
62*2dc7a7e3SShri Abhyankar   ierr = PetscMalloc(nevents*sizeof(PetscScalar),&event->fvalue);CHKERRQ(ierr);
63*2dc7a7e3SShri Abhyankar   ierr = PetscMalloc(nevents*sizeof(PetscScalar),&event->fvalue_prev);CHKERRQ(ierr);
64*2dc7a7e3SShri Abhyankar   ierr = PetscMalloc(nevents*sizeof(PetscBool),&event->terminate);CHKERRQ(ierr);
65*2dc7a7e3SShri Abhyankar   ierr = PetscMalloc(nevents*sizeof(PetscInt),&event->direction);CHKERRQ(ierr);
66*2dc7a7e3SShri Abhyankar   ierr = PetscMalloc(nevents*sizeof(PetscInt),&event->events_zero);CHKERRQ(ierr);
67*2dc7a7e3SShri Abhyankar   event->monitor = eventmonitor;
68*2dc7a7e3SShri Abhyankar   event->postevent = postevent;
69*2dc7a7e3SShri Abhyankar   event->monitorcontext = (void*)mectx;
70*2dc7a7e3SShri Abhyankar   event->nevents = nevents;
71*2dc7a7e3SShri Abhyankar 
72*2dc7a7e3SShri Abhyankar   ierr = TSGetTime(ts,&t);CHKERRQ(ierr);
73*2dc7a7e3SShri Abhyankar   ierr = TSGetTimeStep(ts,&event->initial_timestep);CHKERRQ(ierr);
74*2dc7a7e3SShri Abhyankar   ierr = TSGetSolution(ts,&U);CHKERRQ(ierr);
75*2dc7a7e3SShri Abhyankar   event->ptime_prev = t;
76*2dc7a7e3SShri Abhyankar   ierr = (*event->monitor)(ts,t,U,event->fvalue_prev,event->direction,event->terminate,mectx);CHKERRQ(ierr);
77*2dc7a7e3SShri Abhyankar   ierr = PetscOptionsBegin(PETSC_COMM_WORLD,NULL,"TS Event options","");CHKERRQ(ierr);
78*2dc7a7e3SShri Abhyankar   {
79*2dc7a7e3SShri Abhyankar     event->tol = 1.0e-6;
80*2dc7a7e3SShri Abhyankar     ierr = PetscOptionsReal("-ts_event_tol","","",event->tol,&event->tol,NULL);CHKERRQ(ierr);
81*2dc7a7e3SShri Abhyankar   }
82*2dc7a7e3SShri Abhyankar   ierr = PetscOptionsEnd();CHKERRQ(ierr);
83*2dc7a7e3SShri Abhyankar   PetscFunctionReturn(0);
84*2dc7a7e3SShri Abhyankar }
85*2dc7a7e3SShri Abhyankar 
86*2dc7a7e3SShri Abhyankar #undef __FUNCT__
87*2dc7a7e3SShri Abhyankar #define __FUNCT__ "TSPostEvent"
88*2dc7a7e3SShri Abhyankar PetscErrorCode TSPostEvent(TS ts,PetscInt nevents_zero,PetscInt events_zero[],PetscReal t,Vec U,void *ctx)
89*2dc7a7e3SShri Abhyankar {
90*2dc7a7e3SShri Abhyankar   PetscErrorCode ierr;
91*2dc7a7e3SShri Abhyankar   TSEvent        event=ts->event;
92*2dc7a7e3SShri Abhyankar   PetscBool      terminate=PETSC_FALSE;
93*2dc7a7e3SShri Abhyankar   PetscInt       i;
94*2dc7a7e3SShri Abhyankar   PetscBool      ts_terminate;
95*2dc7a7e3SShri Abhyankar 
96*2dc7a7e3SShri Abhyankar   PetscFunctionBegin;
97*2dc7a7e3SShri Abhyankar   if (event->postevent) {
98*2dc7a7e3SShri Abhyankar     ierr = (*event->postevent)(ts,nevents_zero,events_zero,t,U,ctx);CHKERRQ(ierr);
99*2dc7a7e3SShri Abhyankar   }
100*2dc7a7e3SShri Abhyankar   for(i = 0; i < nevents_zero;i++) {
101*2dc7a7e3SShri Abhyankar     terminate = terminate || event->terminate[events_zero[i]];
102*2dc7a7e3SShri Abhyankar   }
103*2dc7a7e3SShri Abhyankar   ierr = MPI_Allreduce(&terminate,&ts_terminate,1,MPIU_INT,MPI_MAX,((PetscObject)ts)->comm);CHKERRQ(ierr);
104*2dc7a7e3SShri Abhyankar   if (terminate) {
105*2dc7a7e3SShri Abhyankar     ierr = TSSetConvergedReason(ts,TS_CONVERGED_EVENT);CHKERRQ(ierr);
106*2dc7a7e3SShri Abhyankar     event->status = TSEVENT_NONE;
107*2dc7a7e3SShri Abhyankar   } else {
108*2dc7a7e3SShri Abhyankar     event->status = TSEVENT_RESET_NEXTSTEP;
109*2dc7a7e3SShri Abhyankar   }
110*2dc7a7e3SShri Abhyankar   PetscFunctionReturn(0);
111*2dc7a7e3SShri Abhyankar }
112*2dc7a7e3SShri Abhyankar 
113*2dc7a7e3SShri Abhyankar #undef __FUNCT__
114*2dc7a7e3SShri Abhyankar #define __FUNCT__ "TSEventMonitorDestroy"
115*2dc7a7e3SShri Abhyankar PetscErrorCode TSEventMonitorDestroy(TSEvent *event)
116*2dc7a7e3SShri Abhyankar {
117*2dc7a7e3SShri Abhyankar   PetscErrorCode ierr;
118*2dc7a7e3SShri Abhyankar 
119*2dc7a7e3SShri Abhyankar   PetscFunctionBegin;
120*2dc7a7e3SShri Abhyankar   ierr = PetscFree((*event)->fvalue);CHKERRQ(ierr);
121*2dc7a7e3SShri Abhyankar   ierr = PetscFree((*event)->fvalue_prev);CHKERRQ(ierr);
122*2dc7a7e3SShri Abhyankar   ierr = PetscFree((*event)->terminate);CHKERRQ(ierr);
123*2dc7a7e3SShri Abhyankar   ierr = PetscFree((*event)->direction);CHKERRQ(ierr);
124*2dc7a7e3SShri Abhyankar   ierr = PetscFree((*event)->events_zero);CHKERRQ(ierr);
125*2dc7a7e3SShri Abhyankar   ierr = PetscFree(*event);CHKERRQ(ierr);
126*2dc7a7e3SShri Abhyankar   *event = NULL;
127*2dc7a7e3SShri Abhyankar   PetscFunctionReturn(0);
128*2dc7a7e3SShri Abhyankar }
129*2dc7a7e3SShri Abhyankar 
130*2dc7a7e3SShri Abhyankar #undef __FUNCT__
131*2dc7a7e3SShri Abhyankar #define __FUNCT__ "TSEventMonitor"
132*2dc7a7e3SShri Abhyankar PetscErrorCode TSEventMonitor(TS ts)
133*2dc7a7e3SShri Abhyankar {
134*2dc7a7e3SShri Abhyankar   PetscErrorCode ierr;
135*2dc7a7e3SShri Abhyankar   TSEvent        event=ts->event;
136*2dc7a7e3SShri Abhyankar   PetscReal      t;
137*2dc7a7e3SShri Abhyankar   Vec            U;
138*2dc7a7e3SShri Abhyankar   PetscInt       i;
139*2dc7a7e3SShri Abhyankar   PetscReal      dt;
140*2dc7a7e3SShri Abhyankar   PetscInt       status=event->status;
141*2dc7a7e3SShri Abhyankar   PetscInt       rollback=0,in[2],out[2];
142*2dc7a7e3SShri Abhyankar 
143*2dc7a7e3SShri Abhyankar   PetscFunctionBegin;
144*2dc7a7e3SShri Abhyankar 
145*2dc7a7e3SShri Abhyankar   ierr = TSGetTime(ts,&t);CHKERRQ(ierr);
146*2dc7a7e3SShri Abhyankar   ierr = TSGetSolution(ts,&U);CHKERRQ(ierr);
147*2dc7a7e3SShri Abhyankar 
148*2dc7a7e3SShri Abhyankar   ierr = TSGetTimeStep(ts,&dt);CHKERRQ(ierr);
149*2dc7a7e3SShri Abhyankar   if (event->status == TSEVENT_RESET_NEXTSTEP) {
150*2dc7a7e3SShri Abhyankar     /* Take initial time step */
151*2dc7a7e3SShri Abhyankar     dt = event->initial_timestep;
152*2dc7a7e3SShri Abhyankar     ts->time_step = dt;
153*2dc7a7e3SShri Abhyankar     event->status = TSEVENT_NONE;
154*2dc7a7e3SShri Abhyankar   }
155*2dc7a7e3SShri Abhyankar 
156*2dc7a7e3SShri Abhyankar   if (event->status == TSEVENT_NONE) {
157*2dc7a7e3SShri Abhyankar     event->tstepend   = t;
158*2dc7a7e3SShri Abhyankar   }
159*2dc7a7e3SShri Abhyankar 
160*2dc7a7e3SShri Abhyankar   event->nevents_zero = 0;
161*2dc7a7e3SShri Abhyankar 
162*2dc7a7e3SShri Abhyankar   ierr = (*event->monitor)(ts,t,U,event->fvalue,event->direction,event->terminate,event->monitorcontext);CHKERRQ(ierr);
163*2dc7a7e3SShri Abhyankar   if (event->status != TSEVENT_NONE) {
164*2dc7a7e3SShri Abhyankar     for (i=0; i < event->nevents; i++) {
165*2dc7a7e3SShri Abhyankar       if (PetscAbs(event->fvalue[i]) < event->tol) {
166*2dc7a7e3SShri Abhyankar 	event->status = TSEVENT_ZERO;
167*2dc7a7e3SShri Abhyankar 	event->events_zero[event->nevents_zero++] = i;
168*2dc7a7e3SShri Abhyankar       }
169*2dc7a7e3SShri Abhyankar     }
170*2dc7a7e3SShri Abhyankar   }
171*2dc7a7e3SShri Abhyankar 
172*2dc7a7e3SShri Abhyankar   status = event->status;
173*2dc7a7e3SShri Abhyankar   ierr = MPI_Allreduce(&status,&event->status,1,MPIU_INT,MPI_MAX,((PetscObject)ts)->comm);CHKERRQ(ierr);
174*2dc7a7e3SShri Abhyankar 
175*2dc7a7e3SShri Abhyankar   if (event->status == TSEVENT_ZERO) {
176*2dc7a7e3SShri Abhyankar     dt = event->tstepend-t;
177*2dc7a7e3SShri Abhyankar     ts->time_step = dt;
178*2dc7a7e3SShri Abhyankar     ierr = TSPostEvent(ts,event->nevents_zero,event->events_zero,t,U,event->monitorcontext);CHKERRQ(ierr);
179*2dc7a7e3SShri Abhyankar     for (i = 0; i < event->nevents; i++) {
180*2dc7a7e3SShri Abhyankar       event->fvalue_prev[i] = event->fvalue[i];
181*2dc7a7e3SShri Abhyankar     }
182*2dc7a7e3SShri Abhyankar     event->ptime_prev  = t;
183*2dc7a7e3SShri Abhyankar     PetscFunctionReturn(0);
184*2dc7a7e3SShri Abhyankar   }
185*2dc7a7e3SShri Abhyankar 
186*2dc7a7e3SShri Abhyankar   for (i = 0; i < event->nevents; i++) {
187*2dc7a7e3SShri Abhyankar     if ((event->direction[i] < 0 && PetscSign(event->fvalue[i]) <= 0 && PetscSign(event->fvalue_prev[i]) >= 0) || \
188*2dc7a7e3SShri Abhyankar         (event->direction[i] > 0 && PetscSign(event->fvalue[i]) >= 0 && PetscSign(event->fvalue_prev[i]) <= 0) || \
189*2dc7a7e3SShri Abhyankar         (event->direction[i] == 0 && PetscSign(event->fvalue[i])*PetscSign(event->fvalue_prev[i]) <= 0)) {
190*2dc7a7e3SShri Abhyankar 
191*2dc7a7e3SShri Abhyankar       event->status = TSEVENT_LOCATED_INTERVAL;
192*2dc7a7e3SShri Abhyankar       rollback = 1;
193*2dc7a7e3SShri Abhyankar       /* Compute linearly interpolated new time step */
194*2dc7a7e3SShri Abhyankar       dt = PetscMin(dt,-event->fvalue_prev[i]*(t - event->ptime_prev)/(event->fvalue[i] - event->fvalue_prev[i]));
195*2dc7a7e3SShri Abhyankar     }
196*2dc7a7e3SShri Abhyankar   }
197*2dc7a7e3SShri Abhyankar   in[0] = event->status;
198*2dc7a7e3SShri Abhyankar   in[1] = rollback;
199*2dc7a7e3SShri Abhyankar   ierr = MPI_Allreduce(in,out,2,MPIU_INT,MPI_MAX,((PetscObject)ts)->comm);CHKERRQ(ierr);
200*2dc7a7e3SShri Abhyankar 
201*2dc7a7e3SShri Abhyankar   rollback = out[1];
202*2dc7a7e3SShri Abhyankar   if (rollback) {
203*2dc7a7e3SShri Abhyankar     event->status = TSEVENT_LOCATED_INTERVAL;
204*2dc7a7e3SShri Abhyankar   }
205*2dc7a7e3SShri Abhyankar 
206*2dc7a7e3SShri Abhyankar   if (event->status == TSEVENT_LOCATED_INTERVAL) {
207*2dc7a7e3SShri Abhyankar     ierr = TSRollBack(ts);CHKERRQ(ierr);
208*2dc7a7e3SShri Abhyankar     event->status = TSEVENT_PROCESSING;
209*2dc7a7e3SShri Abhyankar   } else {
210*2dc7a7e3SShri Abhyankar     for (i = 0; i < event->nevents; i++) {
211*2dc7a7e3SShri Abhyankar       event->fvalue_prev[i] = event->fvalue[i];
212*2dc7a7e3SShri Abhyankar     }
213*2dc7a7e3SShri Abhyankar     event->ptime_prev  = t;
214*2dc7a7e3SShri Abhyankar     if (event->status == TSEVENT_PROCESSING) {
215*2dc7a7e3SShri Abhyankar       dt = event->tstepend - event->ptime_prev;
216*2dc7a7e3SShri Abhyankar     }
217*2dc7a7e3SShri Abhyankar   }
218*2dc7a7e3SShri Abhyankar   PetscReal time_step;
219*2dc7a7e3SShri Abhyankar   ierr = MPI_Allreduce(&dt,&time_step,1,MPIU_REAL,MPI_MIN,((PetscObject)ts)->comm);CHKERRQ(ierr);
220*2dc7a7e3SShri Abhyankar   ts->time_step = time_step;
221*2dc7a7e3SShri Abhyankar   PetscFunctionReturn(0);
222*2dc7a7e3SShri Abhyankar }
223*2dc7a7e3SShri Abhyankar 
224