1 2 #include <petsc-private/tsimpl.h> /*I "petscts.h" I*/ 3 4 #undef __FUNCT__ 5 #define __FUNCT__ "TSEventMonitorInitialize" 6 /* 7 TSEventMonitorInitialize - Initializes TSEvent for TSSolve 8 */ 9 PetscErrorCode TSEventMonitorInitialize(TS ts) 10 { 11 PetscErrorCode ierr; 12 PetscReal t; 13 Vec U; 14 TSEvent event=ts->event; 15 16 PetscFunctionBegin; 17 18 ierr = TSGetTime(ts,&t);CHKERRQ(ierr); 19 ierr = TSGetTimeStep(ts,&event->initial_timestep);CHKERRQ(ierr); 20 ierr = TSGetSolution(ts,&U);CHKERRQ(ierr); 21 event->ptime_prev = t; 22 ierr = (*event->monitor)(ts,t,U,event->fvalue_prev,event->monitorcontext);CHKERRQ(ierr); 23 24 /* Initialize the event recorder */ 25 event->recorder.ctr = 0; 26 27 PetscFunctionReturn(0); 28 } 29 30 #undef __FUNCT__ 31 #define __FUNCT__ "TSSetEventMonitor" 32 /*@C 33 TSSetEventMonitor - Sets a monitoring function used for detecting events 34 35 Logically Collective on TS 36 37 Input Parameters: 38 + ts - the TS context obtained from TSCreate() 39 . nevents - number of local events 40 . direction - direction of zero crossing to be detected. -1 => Zero crossing in negative direction, 41 +1 => Zero crossing in positive direction, 0 => both ways (one for each event) 42 . terminate - flag to indicate whether time stepping should be terminated after 43 event is detected (one for each event) 44 . eventmonitor - event monitoring routine 45 . postevent - [optional] post-event function 46 - mectx - [optional] user-defined context for private data for the 47 event monitor and post event routine (use NULL if no 48 context is desired) 49 50 Calling sequence of eventmonitor: 51 PetscErrorCode EventMonitor(TS ts,PetscReal t,Vec U,PetscScalar *fvalue,void* mectx) 52 53 Input Parameters: 54 + ts - the TS context 55 . t - current time 56 . U - current iterate 57 - ctx - [optional] context passed with eventmonitor 58 59 Output parameters: 60 . fvalue - function value of events at time t 61 62 Calling sequence of postevent: 63 PetscErrorCode PostEvent(TS ts,PetscInt nevents_zero, PetscInt events_zero, PetscReal t,Vec U,PetscBool forwardsolve,void* ctx) 64 65 Input Parameters: 66 + ts - the TS context 67 . nevents_zero - number of local events whose event function is zero 68 . events_zero - indices of local events which have reached zero 69 . t - current time 70 . U - current solution 71 . forwardsolve - Flag to indicate whether TS is doing a forward solve (1) or adjoint solve (0) 72 - ctx - the context passed with eventmonitor 73 74 Level: intermediate 75 76 .keywords: TS, event, set, monitor 77 78 .seealso: TSCreate(), TSSetTimeStep(), TSSetConvergedReason() 79 @*/ 80 PetscErrorCode TSSetEventMonitor(TS ts,PetscInt nevents,PetscInt *direction,PetscBool *terminate,PetscErrorCode (*eventmonitor)(TS,PetscReal,Vec,PetscScalar*,void*),PetscErrorCode (*postevent)(TS,PetscInt,PetscInt[],PetscReal,Vec,PetscBool,void*),void *mectx) 81 { 82 PetscErrorCode ierr; 83 TSEvent event; 84 PetscInt i; 85 86 PetscFunctionBegin; 87 ierr = PetscNew(&event);CHKERRQ(ierr); 88 ierr = PetscMalloc1(nevents,&event->fvalue);CHKERRQ(ierr); 89 ierr = PetscMalloc1(nevents,&event->fvalue_prev);CHKERRQ(ierr); 90 ierr = PetscMalloc1(nevents,&event->direction);CHKERRQ(ierr); 91 ierr = PetscMalloc1(nevents,&event->terminate);CHKERRQ(ierr); 92 for (i=0; i < nevents; i++) { 93 event->direction[i] = direction[i]; 94 event->terminate[i] = terminate[i]; 95 } 96 ierr = PetscMalloc1(nevents,&event->events_zero);CHKERRQ(ierr); 97 event->monitor = eventmonitor; 98 event->postevent = postevent; 99 event->monitorcontext = (void*)mectx; 100 event->nevents = nevents; 101 102 for(i=0; i < MAXEVENTRECORDERS; i++) { 103 ierr = PetscMalloc1(nevents,&event->recorder.eventidx[i]);CHKERRQ(ierr); 104 } 105 106 ierr = PetscOptionsBegin(PETSC_COMM_WORLD,NULL,"TS Event options","");CHKERRQ(ierr); 107 { 108 event->tol = 1.0e-6; 109 ierr = PetscOptionsReal("-ts_event_tol","","",event->tol,&event->tol,NULL);CHKERRQ(ierr); 110 } 111 ierr = PetscOptionsEnd();CHKERRQ(ierr); 112 ts->event = event; 113 PetscFunctionReturn(0); 114 } 115 116 #undef __FUNCT__ 117 #define __FUNCT__ "TSPostEvent" 118 /* 119 TSPostEvent - Does post event processing by calling the user-defined postevent function 120 121 Logically Collective on TS 122 123 Input Parameters: 124 + ts - the TS context 125 . nevents_zero - number of local events whose event function is zero 126 . events_zero - indices of local events which have reached zero 127 . t - current time 128 . U - current solution 129 . forwardsolve - Flag to indicate whether TS is doing a forward solve (1) or adjoint solve (0) 130 - ctx - the context passed with eventmonitor 131 132 Level: intermediate 133 134 .keywords: TS, event, set, monitor 135 136 .seealso: TSSetEventMonitor(),TSEvent 137 */ 138 #undef __FUNCT__ 139 #define __FUNCT__ "TSPostEvent" 140 PetscErrorCode TSPostEvent(TS ts,PetscInt nevents_zero,PetscInt events_zero[],PetscReal t,Vec U,PetscBool forwardsolve,void *ctx) 141 { 142 PetscErrorCode ierr; 143 TSEvent event=ts->event; 144 PetscBool terminate=PETSC_FALSE; 145 PetscInt i,ctr,stepnum; 146 PetscBool ts_terminate; 147 148 PetscFunctionBegin; 149 if (event->postevent) { 150 ierr = (*event->postevent)(ts,nevents_zero,events_zero,t,U,forwardsolve,ctx);CHKERRQ(ierr); 151 } 152 for(i = 0; i < nevents_zero;i++) { 153 terminate = (PetscBool)(terminate || event->terminate[events_zero[i]]); 154 } 155 ierr = MPI_Allreduce(&terminate,&ts_terminate,1,MPIU_BOOL,MPI_LOR,((PetscObject)ts)->comm);CHKERRQ(ierr); 156 if (terminate) { 157 ierr = TSSetConvergedReason(ts,TS_CONVERGED_EVENT);CHKERRQ(ierr); 158 event->status = TSEVENT_NONE; 159 } else { 160 event->status = TSEVENT_RESET_NEXTSTEP; 161 } 162 163 /* Record the event in the event recorder */ 164 ierr = TSGetTimeStepNumber(ts,&stepnum);CHKERRQ(ierr); 165 ctr = event->recorder.ctr; 166 if (ctr == MAXEVENTRECORDERS) { 167 SETERRQ1(PetscObjectComm((PetscObject)ts),PETSC_ERR_ARG_OUTOFRANGE,"Exceeded limit (=%d) for number of events recorded",MAXEVENTRECORDERS); 168 } 169 event->recorder.time[ctr] = t; 170 event->recorder.stepnum[ctr] = stepnum; 171 event->recorder.nevents[ctr] = nevents_zero; 172 for(i=0; i < nevents_zero; i++) event->recorder.eventidx[ctr][i] = events_zero[i]; 173 event->recorder.ctr++; 174 175 /* Reset the event residual functions as states might get changed by the postevent callback */ 176 ierr = (*event->monitor)(ts,t,U,event->fvalue_prev,event->monitorcontext);CHKERRQ(ierr); 177 event->ptime_prev = t; 178 179 PetscFunctionReturn(0); 180 } 181 182 #undef __FUNCT__ 183 #define __FUNCT__ "TSEventMonitorDestroy" 184 PetscErrorCode TSEventMonitorDestroy(TSEvent *event) 185 { 186 PetscErrorCode ierr; 187 PetscInt i; 188 189 PetscFunctionBegin; 190 ierr = PetscFree((*event)->fvalue);CHKERRQ(ierr); 191 ierr = PetscFree((*event)->fvalue_prev);CHKERRQ(ierr); 192 ierr = PetscFree((*event)->direction);CHKERRQ(ierr); 193 ierr = PetscFree((*event)->terminate);CHKERRQ(ierr); 194 ierr = PetscFree((*event)->events_zero);CHKERRQ(ierr); 195 for(i=0; i < MAXEVENTRECORDERS; i++) { 196 ierr = PetscFree((*event)->recorder.eventidx[i]); 197 } 198 ierr = PetscFree(*event);CHKERRQ(ierr); 199 *event = NULL; 200 PetscFunctionReturn(0); 201 } 202 203 #undef __FUNCT__ 204 #define __FUNCT__ "TSEventMonitor" 205 PetscErrorCode TSEventMonitor(TS ts) 206 { 207 PetscErrorCode ierr; 208 TSEvent event=ts->event; 209 PetscReal t; 210 Vec U; 211 PetscInt i; 212 PetscReal dt; 213 TSEventStatus status = event->status; 214 PetscInt rollback=0,in[2],out[2]; 215 PetscBool forwardsolve=PETSC_TRUE; /* Flag indicating that TS is doing a forward solve */ 216 217 PetscFunctionBegin; 218 219 ierr = TSGetTime(ts,&t);CHKERRQ(ierr); 220 ierr = TSGetSolution(ts,&U);CHKERRQ(ierr); 221 222 ierr = TSGetTimeStep(ts,&dt);CHKERRQ(ierr); 223 if (event->status == TSEVENT_RESET_NEXTSTEP) { 224 /* Take initial time step */ 225 dt = event->initial_timestep; 226 ts->time_step = dt; 227 event->status = TSEVENT_NONE; 228 } 229 230 if (event->status == TSEVENT_NONE) { 231 event->tstepend = t; 232 } 233 234 event->nevents_zero = 0; 235 236 ierr = (*event->monitor)(ts,t,U,event->fvalue,event->monitorcontext);CHKERRQ(ierr); 237 if (event->status != TSEVENT_NONE) { 238 for (i=0; i < event->nevents; i++) { 239 if (PetscAbsScalar(event->fvalue[i]) < event->tol) { 240 event->status = TSEVENT_ZERO; 241 event->events_zero[event->nevents_zero++] = i; 242 } 243 } 244 } 245 246 status = event->status; 247 ierr = MPI_Allreduce((PetscEnum*)&status,(PetscEnum*)&event->status,1,MPIU_ENUM,MPI_MAX,((PetscObject)ts)->comm);CHKERRQ(ierr); 248 249 if (event->status == TSEVENT_ZERO) { 250 ierr = TSPostEvent(ts,event->nevents_zero,event->events_zero,t,U,forwardsolve,event->monitorcontext);CHKERRQ(ierr); 251 dt = event->tstepend-t; 252 if(PetscAbsReal(dt) < PETSC_SMALL) dt += event->initial_timestep; 253 ts->time_step = dt; 254 PetscFunctionReturn(0); 255 } 256 257 for (i = 0; i < event->nevents; i++) { 258 PetscInt fvalue_sign,fvalueprev_sign; 259 fvalue_sign = PetscSign(PetscRealPart(event->fvalue[i])); 260 fvalueprev_sign = PetscSign(PetscRealPart(event->fvalue_prev[i])); 261 if (fvalueprev_sign != 0 && (fvalue_sign != fvalueprev_sign)) { 262 switch (event->direction[i]) { 263 case -1: 264 if (fvalue_sign < 0) { 265 rollback = 1; 266 /* Compute linearly interpolated new time step */ 267 dt = PetscMin(dt,PetscRealPart(-event->fvalue_prev[i]*(t - event->ptime_prev)/(event->fvalue[i] - event->fvalue_prev[i]))); 268 } 269 break; 270 case 1: 271 if (fvalue_sign > 0) { 272 rollback = 1; 273 /* Compute linearly interpolated new time step */ 274 dt = PetscMin(dt,PetscRealPart(-event->fvalue_prev[i]*(t - event->ptime_prev)/(event->fvalue[i] - event->fvalue_prev[i]))); 275 } 276 break; 277 case 0: 278 rollback = 1; 279 /* Compute linearly interpolated new time step */ 280 dt = PetscMin(dt,PetscRealPart(-event->fvalue_prev[i]*(t - event->ptime_prev)/(event->fvalue[i] - event->fvalue_prev[i]))); 281 break; 282 } 283 } 284 } 285 if (rollback) event->status = TSEVENT_LOCATED_INTERVAL; 286 287 in[0] = event->status; 288 in[1] = rollback; 289 ierr = MPI_Allreduce(in,out,2,MPIU_INT,MPI_MAX,((PetscObject)ts)->comm);CHKERRQ(ierr); 290 291 rollback = out[1]; 292 if (rollback) { 293 event->status = TSEVENT_LOCATED_INTERVAL; 294 } 295 296 if (event->status == TSEVENT_LOCATED_INTERVAL) { 297 ierr = TSRollBack(ts);CHKERRQ(ierr); 298 ts->steps--; 299 ts->total_steps--; 300 event->status = TSEVENT_PROCESSING; 301 } else { 302 for (i = 0; i < event->nevents; i++) { 303 event->fvalue_prev[i] = event->fvalue[i]; 304 } 305 event->ptime_prev = t; 306 if (event->status == TSEVENT_PROCESSING) { 307 dt = event->tstepend - event->ptime_prev; 308 } 309 } 310 ierr = MPI_Allreduce(&dt,&(ts->time_step),1,MPIU_REAL,MPIU_MIN,((PetscObject)ts)->comm);CHKERRQ(ierr); 311 PetscFunctionReturn(0); 312 } 313 314 #undef __FUNCT__ 315 #define __FUNCT__ "TSAdjointEventMonitor" 316 PetscErrorCode TSAdjointEventMonitor(TS ts) 317 { 318 PetscErrorCode ierr; 319 TSEvent event=ts->event; 320 PetscReal t; 321 Vec U; 322 PetscInt ctr; 323 PetscBool forwardsolve=PETSC_FALSE; /* Flag indicating that TS is doing an adjoint solve */ 324 325 PetscFunctionBegin; 326 327 ierr = TSGetTime(ts,&t);CHKERRQ(ierr); 328 ierr = TSGetSolution(ts,&U);CHKERRQ(ierr); 329 330 ctr = event->recorder.ctr-1; 331 if(ctr >= 0 && PetscAbsReal(t - event->recorder.time[ctr]) < PETSC_SMALL) { 332 /* Call the user postevent function */ 333 if(event->postevent) { 334 ierr = (*event->postevent)(ts,event->recorder.nevents[ctr],event->recorder.eventidx[ctr],t,U,forwardsolve,event->monitorcontext);CHKERRQ(ierr); 335 event->recorder.ctr--; 336 } 337 } 338 339 PetscBarrier((PetscObject)ts); 340 PetscFunctionReturn(0); 341 } 342 343 344 345