xref: /petsc/src/ts/adapt/interface/tsadapt.c (revision cf90aa19e7fcf9475df7a1b28b419e66e6a747de)
1 
2 #include <petsc/private/tsimpl.h> /*I  "petscts.h" I*/
3 
4 PetscClassId TSADAPT_CLASSID;
5 
6 static PetscFunctionList TSAdaptList;
7 static PetscBool         TSAdaptPackageInitialized;
8 static PetscBool         TSAdaptRegisterAllCalled;
9 
10 PETSC_EXTERN PetscErrorCode TSAdaptCreate_None(TSAdapt);
11 PETSC_EXTERN PetscErrorCode TSAdaptCreate_Basic(TSAdapt);
12 PETSC_EXTERN PetscErrorCode TSAdaptCreate_DSP(TSAdapt);
13 PETSC_EXTERN PetscErrorCode TSAdaptCreate_CFL(TSAdapt);
14 PETSC_EXTERN PetscErrorCode TSAdaptCreate_GLEE(TSAdapt);
15 PETSC_EXTERN PetscErrorCode TSAdaptCreate_History(TSAdapt);
16 
17 /*@C
18    TSAdaptRegister -  adds a TSAdapt implementation
19 
20    Not Collective
21 
22    Input Parameters:
23 +  name_scheme - name of user-defined adaptivity scheme
24 -  routine_create - routine to create method context
25 
26    Notes:
27    TSAdaptRegister() may be called multiple times to add several user-defined families.
28 
29    Sample usage:
30 .vb
31    TSAdaptRegister("my_scheme",MySchemeCreate);
32 .ve
33 
34    Then, your scheme can be chosen with the procedural interface via
35 $     TSAdaptSetType(ts,"my_scheme")
36    or at runtime via the option
37 $     -ts_adapt_type my_scheme
38 
39    Level: advanced
40 
41 .keywords: TSAdapt, register
42 
43 .seealso: TSAdaptRegisterAll()
44 @*/
45 PetscErrorCode  TSAdaptRegister(const char sname[],PetscErrorCode (*function)(TSAdapt))
46 {
47   PetscErrorCode ierr;
48 
49   PetscFunctionBegin;
50   ierr = TSAdaptInitializePackage();CHKERRQ(ierr);
51   ierr = PetscFunctionListAdd(&TSAdaptList,sname,function);CHKERRQ(ierr);
52   PetscFunctionReturn(0);
53 }
54 
55 /*@C
56   TSAdaptRegisterAll - Registers all of the adaptivity schemes in TSAdapt
57 
58   Not Collective
59 
60   Level: advanced
61 
62 .keywords: TSAdapt, register, all
63 
64 .seealso: TSAdaptRegisterDestroy()
65 @*/
66 PetscErrorCode  TSAdaptRegisterAll(void)
67 {
68   PetscErrorCode ierr;
69 
70   PetscFunctionBegin;
71   if (TSAdaptRegisterAllCalled) PetscFunctionReturn(0);
72   TSAdaptRegisterAllCalled = PETSC_TRUE;
73   ierr = TSAdaptRegister(TSADAPTNONE,   TSAdaptCreate_None);CHKERRQ(ierr);
74   ierr = TSAdaptRegister(TSADAPTBASIC,  TSAdaptCreate_Basic);CHKERRQ(ierr);
75   ierr = TSAdaptRegister(TSADAPTDSP,    TSAdaptCreate_DSP);CHKERRQ(ierr);
76   ierr = TSAdaptRegister(TSADAPTCFL,    TSAdaptCreate_CFL);CHKERRQ(ierr);
77   ierr = TSAdaptRegister(TSADAPTGLEE,   TSAdaptCreate_GLEE);CHKERRQ(ierr);
78   ierr = TSAdaptRegister(TSADAPTHISTORY,TSAdaptCreate_History);CHKERRQ(ierr);
79   PetscFunctionReturn(0);
80 }
81 
82 /*@C
83   TSAdaptFinalizePackage - This function destroys everything in the TS package. It is
84   called from PetscFinalize().
85 
86   Level: developer
87 
88 .keywords: Petsc, destroy, package
89 .seealso: PetscFinalize()
90 @*/
91 PetscErrorCode  TSAdaptFinalizePackage(void)
92 {
93   PetscErrorCode ierr;
94 
95   PetscFunctionBegin;
96   ierr = PetscFunctionListDestroy(&TSAdaptList);CHKERRQ(ierr);
97   TSAdaptPackageInitialized = PETSC_FALSE;
98   TSAdaptRegisterAllCalled  = PETSC_FALSE;
99   PetscFunctionReturn(0);
100 }
101 
102 /*@C
103   TSAdaptInitializePackage - This function initializes everything in the TSAdapt package. It is
104   called from PetscDLLibraryRegister() when using dynamic libraries, and on the first call to
105   TSAdaptCreate() when using static libraries.
106 
107   Level: developer
108 
109 .keywords: TSAdapt, initialize, package
110 .seealso: PetscInitialize()
111 @*/
112 PetscErrorCode  TSAdaptInitializePackage(void)
113 {
114   PetscErrorCode ierr;
115 
116   PetscFunctionBegin;
117   if (TSAdaptPackageInitialized) PetscFunctionReturn(0);
118   TSAdaptPackageInitialized = PETSC_TRUE;
119   ierr = PetscClassIdRegister("TSAdapt",&TSADAPT_CLASSID);CHKERRQ(ierr);
120   ierr = TSAdaptRegisterAll();CHKERRQ(ierr);
121   ierr = PetscRegisterFinalize(TSAdaptFinalizePackage);CHKERRQ(ierr);
122   PetscFunctionReturn(0);
123 }
124 
125 /*@C
126   TSAdaptSetType - sets the approach used for the error adapter, currently there is only TSADAPTBASIC and TSADAPTNONE
127 
128   Logicially Collective on TSAdapt
129 
130   Input Parameter:
131 + adapt - the TS adapter, most likely obtained with TSGetAdapt()
132 - type - either  TSADAPTBASIC or TSADAPTNONE
133 
134   Options Database:
135 . -ts_adapt_type <basic or dsp or none> - to set the adapter type
136 
137   Level: intermediate
138 
139 .keywords: TSAdapt, create
140 
141 .seealso: TSGetAdapt(), TSAdaptDestroy(), TSAdaptType, TSAdaptGetType()
142 @*/
143 PetscErrorCode  TSAdaptSetType(TSAdapt adapt,TSAdaptType type)
144 {
145   PetscBool      match;
146   PetscErrorCode ierr,(*r)(TSAdapt);
147 
148   PetscFunctionBegin;
149   PetscValidHeaderSpecific(adapt,TSADAPT_CLASSID,1);
150   PetscValidCharPointer(type,2);
151   ierr = PetscObjectTypeCompare((PetscObject)adapt,type,&match);CHKERRQ(ierr);
152   if (match) PetscFunctionReturn(0);
153   ierr = PetscFunctionListFind(TSAdaptList,type,&r);CHKERRQ(ierr);
154   if (!r) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_UNKNOWN_TYPE,"Unknown TSAdapt type \"%s\" given",type);
155   if (adapt->ops->destroy) {ierr = (*adapt->ops->destroy)(adapt);CHKERRQ(ierr);}
156   ierr = PetscMemzero(adapt->ops,sizeof(struct _TSAdaptOps));CHKERRQ(ierr);
157   ierr = PetscObjectChangeTypeName((PetscObject)adapt,type);CHKERRQ(ierr);
158   ierr = (*r)(adapt);CHKERRQ(ierr);
159   PetscFunctionReturn(0);
160 }
161 
162 /*@C
163   TSAdaptGetType - gets the TS adapter method type (as a string).
164 
165   Not Collective
166 
167   Input Parameter:
168 . adapt - The TS adapter, most likely obtained with TSGetAdapt()
169 
170   Output Parameter:
171 . type - The name of TS adapter method
172 
173   Level: intermediate
174 
175 .keywords: TSAdapt, get, type
176 .seealso TSAdaptSetType()
177 @*/
178 PetscErrorCode TSAdaptGetType(TSAdapt adapt,TSAdaptType *type)
179 {
180   PetscFunctionBegin;
181   PetscValidHeaderSpecific(adapt,TSADAPT_CLASSID,1);
182   PetscValidPointer(type,2);
183   *type = ((PetscObject)adapt)->type_name;
184   PetscFunctionReturn(0);
185 }
186 
187 PetscErrorCode  TSAdaptSetOptionsPrefix(TSAdapt adapt,const char prefix[])
188 {
189   PetscErrorCode ierr;
190 
191   PetscFunctionBegin;
192   PetscValidHeaderSpecific(adapt,TSADAPT_CLASSID,1);
193   ierr = PetscObjectSetOptionsPrefix((PetscObject)adapt,prefix);CHKERRQ(ierr);
194   PetscFunctionReturn(0);
195 }
196 
197 /*@C
198   TSAdaptLoad - Loads a TSAdapt that has been stored in binary  with TSAdaptView().
199 
200   Collective on PetscViewer
201 
202   Input Parameters:
203 + newdm - the newly loaded TSAdapt, this needs to have been created with TSAdaptCreate() or
204            some related function before a call to TSAdaptLoad().
205 - viewer - binary file viewer, obtained from PetscViewerBinaryOpen() or
206            HDF5 file viewer, obtained from PetscViewerHDF5Open()
207 
208    Level: intermediate
209 
210   Notes:
211    The type is determined by the data in the file, any type set into the TSAdapt before this call is ignored.
212 
213   Notes for advanced users:
214   Most users should not need to know the details of the binary storage
215   format, since TSAdaptLoad() and TSAdaptView() completely hide these details.
216   But for anyone who's interested, the standard binary matrix storage
217   format is
218 .vb
219      has not yet been determined
220 .ve
221 
222 .seealso: PetscViewerBinaryOpen(), TSAdaptView(), MatLoad(), VecLoad()
223 @*/
224 PetscErrorCode  TSAdaptLoad(TSAdapt adapt,PetscViewer viewer)
225 {
226   PetscErrorCode ierr;
227   PetscBool      isbinary;
228   char           type[256];
229 
230   PetscFunctionBegin;
231   PetscValidHeaderSpecific(adapt,TSADAPT_CLASSID,1);
232   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
233   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERBINARY,&isbinary);CHKERRQ(ierr);
234   if (!isbinary) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Invalid viewer; open viewer with PetscViewerBinaryOpen()");
235 
236   ierr = PetscViewerBinaryRead(viewer,type,256,NULL,PETSC_CHAR);CHKERRQ(ierr);
237   ierr = TSAdaptSetType(adapt,type);CHKERRQ(ierr);
238   if (adapt->ops->load) {
239     ierr = (*adapt->ops->load)(adapt,viewer);CHKERRQ(ierr);
240   }
241   PetscFunctionReturn(0);
242 }
243 
244 PetscErrorCode  TSAdaptView(TSAdapt adapt,PetscViewer viewer)
245 {
246   PetscErrorCode ierr;
247   PetscBool      iascii,isbinary,isnone;
248 
249   PetscFunctionBegin;
250   PetscValidHeaderSpecific(adapt,TSADAPT_CLASSID,1);
251   if (!viewer) {ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)adapt),&viewer);CHKERRQ(ierr);}
252   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
253   PetscCheckSameComm(adapt,1,viewer,2);
254   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
255   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERBINARY,&isbinary);CHKERRQ(ierr);
256   if (iascii) {
257     ierr = PetscObjectPrintClassNamePrefixType((PetscObject)adapt,viewer);CHKERRQ(ierr);
258     ierr = PetscObjectTypeCompare((PetscObject)adapt,TSADAPTNONE,&isnone);CHKERRQ(ierr);
259     if (!isnone) {
260       if (adapt->always_accept) {ierr = PetscViewerASCIIPrintf(viewer,"  always accepting steps\n");CHKERRQ(ierr);}
261       ierr = PetscViewerASCIIPrintf(viewer,"  safety factor %g\n",(double)adapt->safety);CHKERRQ(ierr);
262       ierr = PetscViewerASCIIPrintf(viewer,"  extra safety factor after step rejection %g\n",(double)adapt->reject_safety);CHKERRQ(ierr);
263       ierr = PetscViewerASCIIPrintf(viewer,"  clip fastest increase %g\n",(double)adapt->clip[1]);CHKERRQ(ierr);
264       ierr = PetscViewerASCIIPrintf(viewer,"  clip fastest decrease %g\n",(double)adapt->clip[0]);CHKERRQ(ierr);
265       ierr = PetscViewerASCIIPrintf(viewer,"  maximum allowed timestep %g\n",(double)adapt->dt_max);CHKERRQ(ierr);
266       ierr = PetscViewerASCIIPrintf(viewer,"  minimum allowed timestep %g\n",(double)adapt->dt_min);CHKERRQ(ierr);
267     }
268     if (adapt->ops->view) {
269       ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
270       ierr = (*adapt->ops->view)(adapt,viewer);CHKERRQ(ierr);
271       ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
272     }
273   } else if (isbinary) {
274     char type[256];
275 
276     /* need to save FILE_CLASS_ID for adapt class */
277     ierr = PetscStrncpy(type,((PetscObject)adapt)->type_name,256);CHKERRQ(ierr);
278     ierr = PetscViewerBinaryWrite(viewer,type,256,PETSC_CHAR,PETSC_FALSE);CHKERRQ(ierr);
279   } else if (adapt->ops->view) {
280     ierr = (*adapt->ops->view)(adapt,viewer);CHKERRQ(ierr);
281   }
282   PetscFunctionReturn(0);
283 }
284 
285 /*@
286    TSAdaptReset - Resets a TSAdapt context.
287 
288    Collective on TS
289 
290    Input Parameter:
291 .  adapt - the TSAdapt context obtained from TSAdaptCreate()
292 
293    Level: developer
294 
295 .seealso: TSAdaptCreate(), TSAdaptDestroy()
296 @*/
297 PetscErrorCode  TSAdaptReset(TSAdapt adapt)
298 {
299   PetscErrorCode ierr;
300 
301   PetscFunctionBegin;
302   PetscValidHeaderSpecific(adapt,TSADAPT_CLASSID,1);
303   if (adapt->ops->reset) {ierr = (*adapt->ops->reset)(adapt);CHKERRQ(ierr);}
304   PetscFunctionReturn(0);
305 }
306 
307 PetscErrorCode  TSAdaptDestroy(TSAdapt *adapt)
308 {
309   PetscErrorCode ierr;
310 
311   PetscFunctionBegin;
312   if (!*adapt) PetscFunctionReturn(0);
313   PetscValidHeaderSpecific(*adapt,TSADAPT_CLASSID,1);
314   if (--((PetscObject)(*adapt))->refct > 0) {*adapt = NULL; PetscFunctionReturn(0);}
315 
316   ierr = TSAdaptReset(*adapt);CHKERRQ(ierr);
317 
318   if ((*adapt)->ops->destroy) {ierr = (*(*adapt)->ops->destroy)(*adapt);CHKERRQ(ierr);}
319   ierr = PetscViewerDestroy(&(*adapt)->monitor);CHKERRQ(ierr);
320   ierr = PetscHeaderDestroy(adapt);CHKERRQ(ierr);
321   PetscFunctionReturn(0);
322 }
323 
324 /*@
325    TSAdaptSetMonitor - Monitor the choices made by the adaptive controller
326 
327    Collective on TSAdapt
328 
329    Input Arguments:
330 +  adapt - adaptive controller context
331 -  flg - PETSC_TRUE to active a monitor, PETSC_FALSE to disable
332 
333    Options Database Keys:
334 .  -ts_adapt_monitor - to turn on monitoring
335 
336    Level: intermediate
337 
338 .seealso: TSAdaptChoose()
339 @*/
340 PetscErrorCode TSAdaptSetMonitor(TSAdapt adapt,PetscBool flg)
341 {
342   PetscErrorCode ierr;
343 
344   PetscFunctionBegin;
345   PetscValidHeaderSpecific(adapt,TSADAPT_CLASSID,1);
346   PetscValidLogicalCollectiveBool(adapt,flg,2);
347   if (flg) {
348     if (!adapt->monitor) {ierr = PetscViewerASCIIOpen(PetscObjectComm((PetscObject)adapt),"stdout",&adapt->monitor);CHKERRQ(ierr);}
349   } else {
350     ierr = PetscViewerDestroy(&adapt->monitor);CHKERRQ(ierr);
351   }
352   PetscFunctionReturn(0);
353 }
354 
355 /*@C
356    TSAdaptSetCheckStage - Set a callback to check convergence for a stage
357 
358    Logically collective on TSAdapt
359 
360    Input Arguments:
361 +  adapt - adaptive controller context
362 -  func - stage check function
363 
364    Arguments of func:
365 $  PetscErrorCode func(TSAdapt adapt,TS ts,PetscBool *accept)
366 
367 +  adapt - adaptive controller context
368 .  ts - time stepping context
369 -  accept - pending choice of whether to accept, can be modified by this routine
370 
371    Level: advanced
372 
373 .seealso: TSAdaptChoose()
374 @*/
375 PetscErrorCode TSAdaptSetCheckStage(TSAdapt adapt,PetscErrorCode (*func)(TSAdapt,TS,PetscReal,Vec,PetscBool*))
376 {
377 
378   PetscFunctionBegin;
379   PetscValidHeaderSpecific(adapt,TSADAPT_CLASSID,1);
380   adapt->checkstage = func;
381   PetscFunctionReturn(0);
382 }
383 
384 /*@
385    TSAdaptSetAlwaysAccept - Set whether to always accept steps regardless of
386    any error or stability condition not meeting the prescribed goal.
387 
388    Logically collective on TSAdapt
389 
390    Input Arguments:
391 +  adapt - time step adaptivity context, usually gotten with TSGetAdapt()
392 -  flag - whether to always accept steps
393 
394    Options Database Keys:
395 .  -ts_adapt_always_accept - to always accept steps
396 
397    Level: intermediate
398 
399 .seealso: TSAdapt, TSAdaptChoose()
400 @*/
401 PetscErrorCode TSAdaptSetAlwaysAccept(TSAdapt adapt,PetscBool flag)
402 {
403   PetscFunctionBegin;
404   PetscValidHeaderSpecific(adapt,TSADAPT_CLASSID,1);
405   PetscValidLogicalCollectiveBool(adapt,flag,2);
406   adapt->always_accept = flag;
407   PetscFunctionReturn(0);
408 }
409 
410 /*@
411    TSAdaptSetSafety - Set safety factors
412 
413    Logically collective on TSAdapt
414 
415    Input Arguments:
416 +  adapt - adaptive controller context
417 .  safety - safety factor relative to target error/stability goal
418 -  reject_safety - extra safety factor to apply if the last step was rejected
419 
420    Options Database Keys:
421 +  -ts_adapt_safety <safety> - to set safety factor
422 -  -ts_adapt_reject_safety <reject_safety> - to set reject safety factor
423 
424    Level: intermediate
425 
426 .seealso: TSAdapt, TSAdaptGetSafety(), TSAdaptChoose()
427 @*/
428 PetscErrorCode TSAdaptSetSafety(TSAdapt adapt,PetscReal safety,PetscReal reject_safety)
429 {
430   PetscFunctionBegin;
431   PetscValidHeaderSpecific(adapt,TSADAPT_CLASSID,1);
432   PetscValidLogicalCollectiveReal(adapt,safety,2);
433   PetscValidLogicalCollectiveReal(adapt,reject_safety,3);
434   if (safety != PETSC_DEFAULT && safety < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Safety factor %g must be non negative",(double)safety);
435   if (safety != PETSC_DEFAULT && safety > 1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Safety factor %g must be less than one",(double)safety);
436   if (reject_safety != PETSC_DEFAULT && reject_safety < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Reject safety factor %g must be non negative",(double)reject_safety);
437   if (reject_safety != PETSC_DEFAULT && reject_safety > 1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Reject safety factor %g must be less than one",(double)reject_safety);
438   if (safety != PETSC_DEFAULT) adapt->safety = safety;
439   if (reject_safety != PETSC_DEFAULT) adapt->reject_safety = reject_safety;
440   PetscFunctionReturn(0);
441 }
442 
443 /*@
444    TSAdaptGetSafety - Get safety factors
445 
446    Not Collective
447 
448    Input Arguments:
449 .  adapt - adaptive controller context
450 
451    Ouput Arguments:
452 .  safety - safety factor relative to target error/stability goal
453 +  reject_safety - extra safety factor to apply if the last step was rejected
454 
455    Level: intermediate
456 
457 .seealso: TSAdapt, TSAdaptSetSafety(), TSAdaptChoose()
458 @*/
459 PetscErrorCode TSAdaptGetSafety(TSAdapt adapt,PetscReal *safety,PetscReal *reject_safety)
460 {
461   PetscFunctionBegin;
462   PetscValidHeaderSpecific(adapt,TSADAPT_CLASSID,1);
463   if (safety)        PetscValidRealPointer(safety,2);
464   if (reject_safety) PetscValidRealPointer(reject_safety,3);
465   if (safety)        *safety        = adapt->safety;
466   if (reject_safety) *reject_safety = adapt->reject_safety;
467   PetscFunctionReturn(0);
468 }
469 
470 /*@
471    TSAdaptSetClip - Sets the admissible decrease/increase factor in step size
472 
473    Logically collective on TSAdapt
474 
475    Input Arguments:
476 +  adapt - adaptive controller context
477 .  low - admissible decrease factor
478 -  high - admissible increase factor
479 
480    Options Database Keys:
481 .  -ts_adapt_clip <low>,<high> - to set admissible time step decrease and increase factors
482 
483    Level: intermediate
484 
485 .seealso: TSAdaptChoose(), TSAdaptGetClip()
486 @*/
487 PetscErrorCode TSAdaptSetClip(TSAdapt adapt,PetscReal low,PetscReal high)
488 {
489   PetscFunctionBegin;
490   PetscValidHeaderSpecific(adapt,TSADAPT_CLASSID,1);
491   PetscValidLogicalCollectiveReal(adapt,low,2);
492   PetscValidLogicalCollectiveReal(adapt,high,3);
493   if (low  != PETSC_DEFAULT && low  < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Decrease factor %g must be non negative",(double)low);
494   if (low  != PETSC_DEFAULT && low  > 1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Decrease factor %g must be less than one",(double)low);
495   if (high != PETSC_DEFAULT && high < 1) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Increase factor %g must be geather than one",(double)high);
496   if (low  != PETSC_DEFAULT) adapt->clip[0] = low;
497   if (high != PETSC_DEFAULT) adapt->clip[1] = high;
498   PetscFunctionReturn(0);
499 }
500 
501 /*@
502    TSAdaptGetClip - Gets the admissible decrease/increase factor in step size
503 
504    Not Collective
505 
506    Input Arguments:
507 .  adapt - adaptive controller context
508 
509    Ouput Arguments:
510 +  low - optional, admissible decrease factor
511 -  high - optional, admissible increase factor
512 
513    Level: intermediate
514 
515 .seealso: TSAdaptChoose(), TSAdaptSetClip()
516 @*/
517 PetscErrorCode TSAdaptGetClip(TSAdapt adapt,PetscReal *low,PetscReal *high)
518 {
519   PetscFunctionBegin;
520   PetscValidHeaderSpecific(adapt,TSADAPT_CLASSID,1);
521   if (low)  PetscValidRealPointer(low,2);
522   if (high) PetscValidRealPointer(high,3);
523   if (low)  *low  = adapt->clip[0];
524   if (high) *high = adapt->clip[1];
525   PetscFunctionReturn(0);
526 }
527 
528 /*@
529    TSAdaptSetStepLimits - Set the minimum and maximum step sizes to be considered by the controller
530 
531    Logically collective on TSAdapt
532 
533    Input Arguments:
534 +  adapt - time step adaptivity context, usually gotten with TSGetAdapt()
535 .  hmin - minimum time step
536 -  hmax - maximum time step
537 
538    Options Database Keys:
539 +  -ts_adapt_dt_min <min> - to set minimum time step
540 -  -ts_adapt_dt_max <max> - to set maximum time step
541 
542    Level: intermediate
543 
544 .seealso: TSAdapt, TSAdaptGetStepLimits(), TSAdaptChoose()
545 @*/
546 PetscErrorCode TSAdaptSetStepLimits(TSAdapt adapt,PetscReal hmin,PetscReal hmax)
547 {
548 
549   PetscFunctionBegin;
550   PetscValidHeaderSpecific(adapt,TSADAPT_CLASSID,1);
551   PetscValidLogicalCollectiveReal(adapt,hmin,2);
552   PetscValidLogicalCollectiveReal(adapt,hmax,3);
553   if (hmin != PETSC_DEFAULT && hmin < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Minimum time step %g must be non negative",(double)hmin);
554   if (hmax != PETSC_DEFAULT && hmax < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Minimum time step %g must be non negative",(double)hmax);
555   if (hmin != PETSC_DEFAULT) adapt->dt_min = hmin;
556   if (hmax != PETSC_DEFAULT) adapt->dt_max = hmax;
557   hmin = adapt->dt_min;
558   hmax = adapt->dt_max;
559   if (hmax <= hmin) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Maximum time step %g must geather than minimum time step %g",(double)hmax,(double)hmin);
560   PetscFunctionReturn(0);
561 }
562 
563 /*@
564    TSAdaptGetStepLimits - Get the minimum and maximum step sizes to be considered by the controller
565 
566    Not Collective
567 
568    Input Arguments:
569 .  adapt - time step adaptivity context, usually gotten with TSGetAdapt()
570 
571    Output Arguments:
572 +  hmin - minimum time step
573 -  hmax - maximum time step
574 
575    Level: intermediate
576 
577 .seealso: TSAdapt, TSAdaptSetStepLimits(), TSAdaptChoose()
578 @*/
579 PetscErrorCode TSAdaptGetStepLimits(TSAdapt adapt,PetscReal *hmin,PetscReal *hmax)
580 {
581 
582   PetscFunctionBegin;
583   PetscValidHeaderSpecific(adapt,TSADAPT_CLASSID,1);
584   if (hmin) PetscValidRealPointer(hmin,2);
585   if (hmax) PetscValidRealPointer(hmax,3);
586   if (hmin) *hmin = adapt->dt_min;
587   if (hmax) *hmax = adapt->dt_max;
588   PetscFunctionReturn(0);
589 }
590 
591 /*
592    TSAdaptSetFromOptions - Sets various TSAdapt parameters from user options.
593 
594    Collective on TSAdapt
595 
596    Input Parameter:
597 .  adapt - the TSAdapt context
598 
599    Options Database Keys:
600 +  -ts_adapt_type <type> - algorithm to use for adaptivity
601 .  -ts_adapt_always_accept - always accept steps regardless of error/stability goals
602 .  -ts_adapt_safety <safety> - safety factor relative to target error/stability goal
603 .  -ts_adapt_reject_safety <safety> - extra safety factor to apply if the last step was rejected
604 .  -ts_adapt_clip <low,high> - admissible time step decrease and increase factors
605 .  -ts_adapt_dt_min <min> - minimum timestep to use
606 .  -ts_adapt_dt_max <max> - maximum timestep to use
607 .  -ts_adapt_scale_solve_failed <scale> - scale timestep by this factor if a solve fails
608 -  -ts_adapt_wnormtype <2 or infinity> - type of norm for computing error estimates
609 
610    Level: advanced
611 
612    Notes:
613    This function is automatically called by TSSetFromOptions()
614 
615 .keywords: TS, TSGetAdapt(), TSAdaptSetType(), TSAdaptSetStepLimits()
616 
617 .seealso: TSGetAdapt(), TSAdaptSetType(), TSAdaptSetAlwaysAccept(), TSAdaptSetSafety(),
618           TSAdaptSetClip(), TSAdaptSetStepLimits(), TSAdaptSetMonitor()
619 */
620 PetscErrorCode  TSAdaptSetFromOptions(PetscOptionItems *PetscOptionsObject,TSAdapt adapt)
621 {
622   PetscErrorCode ierr;
623   char           type[256] = TSADAPTBASIC;
624   PetscReal      safety,reject_safety,clip[2],hmin,hmax;
625   PetscBool      set,flg;
626   PetscInt       two;
627 
628   PetscFunctionBegin;
629   PetscValidHeaderSpecific(adapt,TSADAPT_CLASSID,1);
630   /* This should use PetscOptionsBegin() if/when this becomes an object used outside of TS, but currently this
631    * function can only be called from inside TSSetFromOptions()  */
632   ierr = PetscOptionsHead(PetscOptionsObject,"TS Adaptivity options");CHKERRQ(ierr);
633   ierr = PetscOptionsFList("-ts_adapt_type","Algorithm to use for adaptivity","TSAdaptSetType",TSAdaptList,((PetscObject)adapt)->type_name ? ((PetscObject)adapt)->type_name : type,type,sizeof(type),&flg);CHKERRQ(ierr);
634   if (flg || !((PetscObject)adapt)->type_name) {
635     ierr = TSAdaptSetType(adapt,type);CHKERRQ(ierr);
636   }
637 
638   ierr = PetscOptionsBool("-ts_adapt_always_accept","Always accept the step","TSAdaptSetAlwaysAccept",adapt->always_accept,&flg,&set);CHKERRQ(ierr);
639   if (set) {ierr = TSAdaptSetAlwaysAccept(adapt,flg);CHKERRQ(ierr);}
640 
641   safety = adapt->safety; reject_safety = adapt->reject_safety;
642   ierr = PetscOptionsReal("-ts_adapt_safety","Safety factor relative to target error/stability goal","TSAdaptSetSafety",safety,&safety,&set);CHKERRQ(ierr);
643   ierr = PetscOptionsReal("-ts_adapt_reject_safety","Extra safety factor to apply if the last step was rejected","TSAdaptSetSafety",reject_safety,&reject_safety,&flg);CHKERRQ(ierr);
644   if (set || flg) {ierr = TSAdaptSetSafety(adapt,safety,reject_safety);CHKERRQ(ierr);}
645 
646   two = 2; clip[0] = adapt->clip[0]; clip[1] = adapt->clip[1];
647   ierr = PetscOptionsRealArray("-ts_adapt_clip","Admissible decrease/increase factor in step size","TSAdaptSetClip",clip,&two,&set);CHKERRQ(ierr);
648   if (set && (two != 2)) SETERRQ(PetscObjectComm((PetscObject)adapt),PETSC_ERR_ARG_OUTOFRANGE,"Must give exactly two values to -ts_adapt_clip");
649   if (set) {ierr = TSAdaptSetClip(adapt,clip[0],clip[1]);CHKERRQ(ierr);}
650 
651   hmin = adapt->dt_min; hmax = adapt->dt_max;
652   ierr = PetscOptionsReal("-ts_adapt_dt_min","Minimum time step considered","TSAdaptSetStepLimits",hmin,&hmin,&set);CHKERRQ(ierr);
653   ierr = PetscOptionsReal("-ts_adapt_dt_max","Maximum time step considered","TSAdaptSetStepLimits",hmax,&hmax,&flg);CHKERRQ(ierr);
654   if (set || flg) {ierr = TSAdaptSetStepLimits(adapt,hmin,hmax);CHKERRQ(ierr);}
655 
656   ierr = PetscOptionsReal("-ts_adapt_scale_solve_failed","Scale step by this factor if solve fails","",adapt->scale_solve_failed,&adapt->scale_solve_failed,NULL);CHKERRQ(ierr);
657 
658   ierr = PetscOptionsEnum("-ts_adapt_wnormtype","Type of norm computed for error estimation","",NormTypes,(PetscEnum)adapt->wnormtype,(PetscEnum*)&adapt->wnormtype,NULL);CHKERRQ(ierr);
659   if (adapt->wnormtype != NORM_2 && adapt->wnormtype != NORM_INFINITY) SETERRQ(PetscObjectComm((PetscObject)adapt),PETSC_ERR_SUP,"Only 2-norm and infinite norm supported");
660 
661   ierr = PetscOptionsBool("-ts_adapt_monitor","Print choices made by adaptive controller","TSAdaptSetMonitor",adapt->monitor ? PETSC_TRUE : PETSC_FALSE,&flg,&set);CHKERRQ(ierr);
662   if (set) {ierr = TSAdaptSetMonitor(adapt,flg);CHKERRQ(ierr);}
663 
664   if (adapt->ops->setfromoptions) {ierr = (*adapt->ops->setfromoptions)(PetscOptionsObject,adapt);CHKERRQ(ierr);}
665   ierr = PetscOptionsTail();CHKERRQ(ierr);
666   PetscFunctionReturn(0);
667 }
668 
669 /*@
670    TSAdaptCandidatesClear - clear any previously set candidate schemes
671 
672    Logically collective on TSAdapt
673 
674    Input Argument:
675 .  adapt - adaptive controller
676 
677    Level: developer
678 
679 .seealso: TSAdapt, TSAdaptCreate(), TSAdaptCandidateAdd(), TSAdaptChoose()
680 @*/
681 PetscErrorCode TSAdaptCandidatesClear(TSAdapt adapt)
682 {
683   PetscErrorCode ierr;
684 
685   PetscFunctionBegin;
686   PetscValidHeaderSpecific(adapt,TSADAPT_CLASSID,1);
687   ierr = PetscMemzero(&adapt->candidates,sizeof(adapt->candidates));CHKERRQ(ierr);
688   PetscFunctionReturn(0);
689 }
690 
691 /*@C
692    TSAdaptCandidateAdd - add a candidate scheme for the adaptive controller to select from
693 
694    Logically collective on TSAdapt
695 
696    Input Arguments:
697 +  adapt - time step adaptivity context, obtained with TSGetAdapt() or TSAdaptCreate()
698 .  name - name of the candidate scheme to add
699 .  order - order of the candidate scheme
700 .  stageorder - stage order of the candidate scheme
701 .  ccfl - stability coefficient relative to explicit Euler, used for CFL constraints
702 .  cost - relative measure of the amount of work required for the candidate scheme
703 -  inuse - indicates that this scheme is the one currently in use, this flag can only be set for one scheme
704 
705    Note:
706    This routine is not available in Fortran.
707 
708    Level: developer
709 
710 .seealso: TSAdaptCandidatesClear(), TSAdaptChoose()
711 @*/
712 PetscErrorCode TSAdaptCandidateAdd(TSAdapt adapt,const char name[],PetscInt order,PetscInt stageorder,PetscReal ccfl,PetscReal cost,PetscBool inuse)
713 {
714   PetscInt c;
715 
716   PetscFunctionBegin;
717   PetscValidHeaderSpecific(adapt,TSADAPT_CLASSID,1);
718   if (order < 1) SETERRQ1(PetscObjectComm((PetscObject)adapt),PETSC_ERR_ARG_OUTOFRANGE,"Classical order %D must be a positive integer",order);
719   if (inuse) {
720     if (adapt->candidates.inuse_set) SETERRQ(PetscObjectComm((PetscObject)adapt),PETSC_ERR_ARG_WRONGSTATE,"Cannot set the inuse method twice, maybe forgot to call TSAdaptCandidatesClear()");
721     adapt->candidates.inuse_set = PETSC_TRUE;
722   }
723   /* first slot if this is the current scheme, otherwise the next available slot */
724   c = inuse ? 0 : !adapt->candidates.inuse_set + adapt->candidates.n;
725 
726   adapt->candidates.name[c]       = name;
727   adapt->candidates.order[c]      = order;
728   adapt->candidates.stageorder[c] = stageorder;
729   adapt->candidates.ccfl[c]       = ccfl;
730   adapt->candidates.cost[c]       = cost;
731   adapt->candidates.n++;
732   PetscFunctionReturn(0);
733 }
734 
735 /*@C
736    TSAdaptCandidatesGet - Get the list of candidate orders of accuracy and cost
737 
738    Not Collective
739 
740    Input Arguments:
741 .  adapt - time step adaptivity context
742 
743    Output Arguments:
744 +  n - number of candidate schemes, always at least 1
745 .  order - the order of each candidate scheme
746 .  stageorder - the stage order of each candidate scheme
747 .  ccfl - the CFL coefficient of each scheme
748 -  cost - the relative cost of each scheme
749 
750    Level: developer
751 
752    Note:
753    The current scheme is always returned in the first slot
754 
755 .seealso: TSAdaptCandidatesClear(), TSAdaptCandidateAdd(), TSAdaptChoose()
756 @*/
757 PetscErrorCode TSAdaptCandidatesGet(TSAdapt adapt,PetscInt *n,const PetscInt **order,const PetscInt **stageorder,const PetscReal **ccfl,const PetscReal **cost)
758 {
759   PetscFunctionBegin;
760   PetscValidHeaderSpecific(adapt,TSADAPT_CLASSID,1);
761   if (n) *n = adapt->candidates.n;
762   if (order) *order = adapt->candidates.order;
763   if (stageorder) *stageorder = adapt->candidates.stageorder;
764   if (ccfl) *ccfl = adapt->candidates.ccfl;
765   if (cost) *cost = adapt->candidates.cost;
766   PetscFunctionReturn(0);
767 }
768 
769 /*@C
770    TSAdaptChoose - choose which method and step size to use for the next step
771 
772    Collective on TSAdapt
773 
774    Input Arguments:
775 +  adapt - adaptive contoller
776 -  h - current step size
777 
778    Output Arguments:
779 +  next_sc - optional, scheme to use for the next step
780 .  next_h - step size to use for the next step
781 -  accept - PETSC_TRUE to accept the current step, PETSC_FALSE to repeat the current step with the new step size
782 
783    Note:
784    The input value of parameter accept is retained from the last time step, so it will be PETSC_FALSE if the step is
785    being retried after an initial rejection.
786 
787    Level: developer
788 
789 .seealso: TSAdapt, TSAdaptCandidatesClear(), TSAdaptCandidateAdd()
790 @*/
791 PetscErrorCode TSAdaptChoose(TSAdapt adapt,TS ts,PetscReal h,PetscInt *next_sc,PetscReal *next_h,PetscBool *accept)
792 {
793   PetscErrorCode ierr;
794   PetscInt       ncandidates = adapt->candidates.n;
795   PetscInt       scheme = 0;
796   PetscReal      wlte = -1.0;
797   PetscReal      wltea = -1.0;
798   PetscReal      wlter = -1.0;
799 
800   PetscFunctionBegin;
801   PetscValidHeaderSpecific(adapt,TSADAPT_CLASSID,1);
802   PetscValidHeaderSpecific(ts,TS_CLASSID,2);
803   if (next_sc) PetscValidIntPointer(next_sc,4);
804   PetscValidPointer(next_h,5);
805   PetscValidIntPointer(accept,6);
806   if (next_sc) *next_sc = 0;
807 
808   /* Do not mess with adaptivity while handling events*/
809   if (ts->event && ts->event->status != TSEVENT_NONE) {
810     *next_h = h;
811     *accept = PETSC_TRUE;
812     PetscFunctionReturn(0);
813   }
814 
815   ierr = (*adapt->ops->choose)(adapt,ts,h,&scheme,next_h,accept,&wlte,&wltea,&wlter);CHKERRQ(ierr);
816   if (scheme < 0 || (ncandidates > 0 && scheme >= ncandidates)) SETERRQ2(PetscObjectComm((PetscObject)adapt),PETSC_ERR_ARG_OUTOFRANGE,"Chosen scheme %D not in valid range 0..%D",scheme,ncandidates-1);
817   if (*next_h < 0) SETERRQ1(PetscObjectComm((PetscObject)adapt),PETSC_ERR_ARG_OUTOFRANGE,"Computed step size %g must be positive",(double)*next_h);
818   if (next_sc) *next_sc = scheme;
819 
820   if (*accept && ts->exact_final_time == TS_EXACTFINALTIME_MATCHSTEP) {
821     /* Increase/reduce step size if end time of next step is close to or overshoots max time */
822     PetscReal t = ts->ptime + ts->time_step, h = *next_h;
823     PetscReal tend = t + h, tmax = ts->max_time, hmax = tmax - t;
824     PetscReal a = (PetscReal)(1.0 + adapt->matchstepfac[0]);
825     PetscReal b = adapt->matchstepfac[1];
826     if (t < tmax && tend > tmax) *next_h = hmax;
827     if (t < tmax && tend < tmax && h*b > hmax) *next_h = hmax/2;
828     if (t < tmax && tend < tmax && h*a > hmax) *next_h = hmax;
829   }
830 
831   if (adapt->monitor) {
832     const char *sc_name = (scheme < ncandidates) ? adapt->candidates.name[scheme] : "";
833     ierr = PetscViewerASCIIAddTab(adapt->monitor,((PetscObject)adapt)->tablevel);CHKERRQ(ierr);
834     if (wlte < 0) {
835       ierr = PetscViewerASCIIPrintf(adapt->monitor,"    TSAdapt %s %s %D:%s step %3D %s t=%-11g+%10.3e dt=%-10.3e\n",((PetscObject)adapt)->type_name,((PetscObject)ts)->type_name,scheme,sc_name,ts->steps,*accept ? "accepted" : "rejected",(double)ts->ptime,(double)h,(double)*next_h);CHKERRQ(ierr);
836     } else {
837       ierr = PetscViewerASCIIPrintf(adapt->monitor,"    TSAdapt %s %s %D:%s step %3D %s t=%-11g+%10.3e dt=%-10.3e wlte=%5.3g  wltea=%5.3g wlter=%5.3g\n",((PetscObject)adapt)->type_name,((PetscObject)ts)->type_name,scheme,sc_name,ts->steps,*accept ? "accepted" : "rejected",(double)ts->ptime,(double)h,(double)*next_h,(double)wlte,(double)wltea,(double)wlter);CHKERRQ(ierr);
838     }
839     ierr = PetscViewerASCIISubtractTab(adapt->monitor,((PetscObject)adapt)->tablevel);CHKERRQ(ierr);
840   }
841   PetscFunctionReturn(0);
842 }
843 
844 /*@
845    TSAdaptCheckStage - checks whether to accept a stage, (e.g. reject and change time step size if nonlinear solve fails)
846 
847    Collective on TSAdapt
848 
849    Input Arguments:
850 +  adapt - adaptive controller context
851 .  ts - time stepper
852 .  t - Current simulation time
853 -  Y - Current solution vector
854 
855    Output Arguments:
856 .  accept - PETSC_TRUE to accept the stage, PETSC_FALSE to reject
857 
858    Level: developer
859 
860 .seealso:
861 @*/
862 PetscErrorCode TSAdaptCheckStage(TSAdapt adapt,TS ts,PetscReal t,Vec Y,PetscBool *accept)
863 {
864   PetscErrorCode      ierr;
865   SNESConvergedReason snesreason = SNES_CONVERGED_ITERATING;
866 
867   PetscFunctionBegin;
868   PetscValidHeaderSpecific(adapt,TSADAPT_CLASSID,1);
869   PetscValidHeaderSpecific(ts,TS_CLASSID,2);
870   PetscValidIntPointer(accept,3);
871 
872   if (ts->snes) {ierr = SNESGetConvergedReason(ts->snes,&snesreason);CHKERRQ(ierr);}
873   if (snesreason < 0) {
874     *accept = PETSC_FALSE;
875     if (++ts->num_snes_failures >= ts->max_snes_failures && ts->max_snes_failures > 0) {
876       ts->reason = TS_DIVERGED_NONLINEAR_SOLVE;
877       ierr = PetscInfo2(ts,"Step=%D, nonlinear solve failures %D greater than current TS allowed, stopping solve\n",ts->steps,ts->num_snes_failures);CHKERRQ(ierr);
878       if (adapt->monitor) {
879         ierr = PetscViewerASCIIAddTab(adapt->monitor,((PetscObject)adapt)->tablevel);CHKERRQ(ierr);
880         ierr = PetscViewerASCIIPrintf(adapt->monitor,"    TSAdapt %s step %3D stage rejected t=%-11g+%10.3e, nonlinear solve failures %D greater than current TS allowed\n",((PetscObject)adapt)->type_name,ts->steps,(double)ts->ptime,(double)ts->time_step,ts->num_snes_failures);CHKERRQ(ierr);
881         ierr = PetscViewerASCIISubtractTab(adapt->monitor,((PetscObject)adapt)->tablevel);CHKERRQ(ierr);
882       }
883     }
884   } else {
885     *accept = PETSC_TRUE;
886     ierr = TSFunctionDomainError(ts,t,Y,accept);CHKERRQ(ierr);
887     if(*accept && adapt->checkstage) {
888       ierr = (*adapt->checkstage)(adapt,ts,t,Y,accept);CHKERRQ(ierr);
889     }
890   }
891 
892   if(!(*accept) && !ts->reason) {
893     PetscReal dt,new_dt;
894     ierr = TSGetTimeStep(ts,&dt);CHKERRQ(ierr);
895     new_dt = dt * adapt->scale_solve_failed;
896     ierr = TSSetTimeStep(ts,new_dt);CHKERRQ(ierr);
897     adapt->timestepjustincreased += 4;
898     if (adapt->monitor) {
899       ierr = PetscViewerASCIIAddTab(adapt->monitor,((PetscObject)adapt)->tablevel);CHKERRQ(ierr);
900       ierr = PetscViewerASCIIPrintf(adapt->monitor,"    TSAdapt %s step %3D stage rejected (%s) t=%-11g+%10.3e retrying with dt=%-10.3e\n",((PetscObject)adapt)->type_name,ts->steps,SNESConvergedReasons[snesreason],(double)ts->ptime,(double)dt,(double)new_dt);CHKERRQ(ierr);
901       ierr = PetscViewerASCIISubtractTab(adapt->monitor,((PetscObject)adapt)->tablevel);CHKERRQ(ierr);
902     }
903   }
904   PetscFunctionReturn(0);
905 }
906 
907 /*@
908   TSAdaptCreate - create an adaptive controller context for time stepping
909 
910   Collective on MPI_Comm
911 
912   Input Parameter:
913 . comm - The communicator
914 
915   Output Parameter:
916 . adapt - new TSAdapt object
917 
918   Level: developer
919 
920   Notes:
921   TSAdapt creation is handled by TS, so users should not need to call this function.
922 
923 .keywords: TSAdapt, create
924 .seealso: TSGetAdapt(), TSAdaptSetType(), TSAdaptDestroy()
925 @*/
926 PetscErrorCode  TSAdaptCreate(MPI_Comm comm,TSAdapt *inadapt)
927 {
928   PetscErrorCode ierr;
929   TSAdapt        adapt;
930 
931   PetscFunctionBegin;
932   PetscValidPointer(inadapt,1);
933   *inadapt = NULL;
934   ierr = TSAdaptInitializePackage();CHKERRQ(ierr);
935 
936   ierr = PetscHeaderCreate(adapt,TSADAPT_CLASSID,"TSAdapt","Time stepping adaptivity","TS",comm,TSAdaptDestroy,TSAdaptView);CHKERRQ(ierr);
937 
938   adapt->always_accept      = PETSC_FALSE;
939   adapt->safety             = 0.9;
940   adapt->reject_safety      = 0.5;
941   adapt->clip[0]            = 0.1;
942   adapt->clip[1]            = 10.;
943   adapt->dt_min             = 1e-20;
944   adapt->dt_max             = 1e+20;
945   adapt->scale_solve_failed = 0.25;
946   /* these two safety factors are not public, and they are used only in the TS_EXACTFINALTIME_MATCHSTEP case
947      to prevent from situations were unreasonably small time steps are taken in order to match the final time */
948   adapt->matchstepfac[0]    = 0.01; /* allow 1% step size increase in the last step */
949   adapt->matchstepfac[1]    = 2.0;  /* halve last step if it is greater than what remains divided this factor */
950   adapt->wnormtype          = NORM_2;
951 
952   *inadapt = adapt;
953   PetscFunctionReturn(0);
954 }
955