xref: /petsc/src/ts/adapt/interface/tsadapt.c (revision 7453f77509fc006cbcc7de2dd772f60dc49feac5)
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_GLEE(TSAdapt);
11 PETSC_EXTERN PetscErrorCode TSAdaptCreate_None(TSAdapt);
12 PETSC_EXTERN PetscErrorCode TSAdaptCreate_Basic(TSAdapt);
13 PETSC_EXTERN PetscErrorCode TSAdaptCreate_CFL(TSAdapt);
14 
15 #undef __FUNCT__
16 #define __FUNCT__ "TSAdaptRegister"
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 = PetscFunctionListAdd(&TSAdaptList,sname,function);CHKERRQ(ierr);
51   PetscFunctionReturn(0);
52 }
53 
54 #undef __FUNCT__
55 #define __FUNCT__ "TSAdaptRegisterAll"
56 /*@C
57   TSAdaptRegisterAll - Registers all of the adaptivity schemes in TSAdapt
58 
59   Not Collective
60 
61   Level: advanced
62 
63 .keywords: TSAdapt, register, all
64 
65 .seealso: TSAdaptRegisterDestroy()
66 @*/
67 PetscErrorCode  TSAdaptRegisterAll(void)
68 {
69   PetscErrorCode ierr;
70 
71   PetscFunctionBegin;
72   if (TSAdaptRegisterAllCalled) PetscFunctionReturn(0);
73   TSAdaptRegisterAllCalled = PETSC_TRUE;
74   ierr = TSAdaptRegister(TSADAPTGLEE ,TSAdaptCreate_GLEE);CHKERRQ(ierr);
75   ierr = TSAdaptRegister(TSADAPTNONE, TSAdaptCreate_None);CHKERRQ(ierr);
76   ierr = TSAdaptRegister(TSADAPTBASIC,TSAdaptCreate_Basic);CHKERRQ(ierr);
77   ierr = TSAdaptRegister(TSADAPTCFL,  TSAdaptCreate_CFL);CHKERRQ(ierr);
78   PetscFunctionReturn(0);
79 }
80 
81 #undef __FUNCT__
82 #define __FUNCT__ "TSAdaptFinalizePackage"
83 /*@C
84   TSAdaptFinalizePackage - This function destroys everything in the TS package. It is
85   called from PetscFinalize().
86 
87   Level: developer
88 
89 .keywords: Petsc, destroy, package
90 .seealso: PetscFinalize()
91 @*/
92 PetscErrorCode  TSAdaptFinalizePackage(void)
93 {
94   PetscErrorCode ierr;
95 
96   PetscFunctionBegin;
97   ierr = PetscFunctionListDestroy(&TSAdaptList);CHKERRQ(ierr);
98   TSAdaptPackageInitialized = PETSC_FALSE;
99   TSAdaptRegisterAllCalled  = PETSC_FALSE;
100   PetscFunctionReturn(0);
101 }
102 
103 #undef __FUNCT__
104 #define __FUNCT__ "TSAdaptInitializePackage"
105 /*@C
106   TSAdaptInitializePackage - This function initializes everything in the TSAdapt package. It is
107   called from PetscDLLibraryRegister() when using dynamic libraries, and on the first call to
108   TSCreate_GLLE() when using static libraries.
109 
110   Level: developer
111 
112 .keywords: TSAdapt, initialize, package
113 .seealso: PetscInitialize()
114 @*/
115 PetscErrorCode  TSAdaptInitializePackage(void)
116 {
117   PetscErrorCode ierr;
118 
119   PetscFunctionBegin;
120   if (TSAdaptPackageInitialized) PetscFunctionReturn(0);
121   TSAdaptPackageInitialized = PETSC_TRUE;
122   ierr = PetscClassIdRegister("TSAdapt",&TSADAPT_CLASSID);CHKERRQ(ierr);
123   ierr = TSAdaptRegisterAll();CHKERRQ(ierr);
124   ierr = PetscRegisterFinalize(TSAdaptFinalizePackage);CHKERRQ(ierr);
125   PetscFunctionReturn(0);
126 }
127 
128 #undef __FUNCT__
129 #define __FUNCT__ "TSAdaptSetType"
130 /*@C
131   TSAdaptSetType - sets the approach used for the error adapter, currently there is only TSADAPTBASIC and TSADAPTNONE
132 
133   Logicially Collective on TSAdapt
134 
135   Input Parameter:
136 + adapt - the TS error adapter, most likely obtained with TSGetAdapt()
137 - type - either  TSADAPTBASIC or TSADAPTNONE
138 
139   Options Database:
140 .  -ts_adapt_type basic or none - to setting the adapter type
141 
142   Level: intermediate
143 
144 .keywords: TSAdapt, create
145 
146 .seealso: TSGetAdapt(), TSAdaptDestroy(), TSAdaptType, TSAdaptGetType()
147 @*/
148 PetscErrorCode  TSAdaptSetType(TSAdapt adapt,TSAdaptType type)
149 {
150   PetscBool      match;
151   PetscErrorCode ierr,(*r)(TSAdapt);
152 
153   PetscFunctionBegin;
154   PetscValidHeaderSpecific(adapt,TSADAPT_CLASSID,1);
155   ierr = PetscObjectTypeCompare((PetscObject)adapt,type,&match);CHKERRQ(ierr);
156   if (match) PetscFunctionReturn(0);
157   ierr = PetscFunctionListFind(TSAdaptList,type,&r);CHKERRQ(ierr);
158   if (!r) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_UNKNOWN_TYPE,"Unknown TSAdapt type \"%s\" given",type);
159   if (adapt->ops->destroy) {ierr = (*adapt->ops->destroy)(adapt);CHKERRQ(ierr);}
160   ierr = PetscMemzero(adapt->ops,sizeof(struct _TSAdaptOps));CHKERRQ(ierr);
161   ierr = PetscObjectChangeTypeName((PetscObject)adapt,type);CHKERRQ(ierr);
162   ierr = (*r)(adapt);CHKERRQ(ierr);
163   PetscFunctionReturn(0);
164 }
165 
166 #undef __FUNCT__
167 #define __FUNCT__ "TSAdaptSetOptionsPrefix"
168 PetscErrorCode  TSAdaptSetOptionsPrefix(TSAdapt adapt,const char prefix[])
169 {
170   PetscErrorCode ierr;
171 
172   PetscFunctionBegin;
173   PetscValidHeaderSpecific(adapt,TSADAPT_CLASSID,1);
174   ierr = PetscObjectSetOptionsPrefix((PetscObject)adapt,prefix);CHKERRQ(ierr);
175   PetscFunctionReturn(0);
176 }
177 
178 #undef __FUNCT__
179 #define __FUNCT__ "TSAdaptLoad"
180 /*@C
181   TSAdaptLoad - Loads a TSAdapt that has been stored in binary  with TSAdaptView().
182 
183   Collective on PetscViewer
184 
185   Input Parameters:
186 + newdm - the newly loaded TSAdapt, this needs to have been created with TSAdaptCreate() or
187            some related function before a call to TSAdaptLoad().
188 - viewer - binary file viewer, obtained from PetscViewerBinaryOpen() or
189            HDF5 file viewer, obtained from PetscViewerHDF5Open()
190 
191    Level: intermediate
192 
193   Notes:
194    The type is determined by the data in the file, any type set into the TSAdapt before this call is ignored.
195 
196   Notes for advanced users:
197   Most users should not need to know the details of the binary storage
198   format, since TSAdaptLoad() and TSAdaptView() completely hide these details.
199   But for anyone who's interested, the standard binary matrix storage
200   format is
201 .vb
202      has not yet been determined
203 .ve
204 
205 .seealso: PetscViewerBinaryOpen(), TSAdaptView(), MatLoad(), VecLoad()
206 @*/
207 PetscErrorCode  TSAdaptLoad(TSAdapt adapt,PetscViewer viewer)
208 {
209   PetscErrorCode ierr;
210   PetscBool      isbinary;
211   char           type[256];
212 
213   PetscFunctionBegin;
214   PetscValidHeaderSpecific(adapt,TSADAPT_CLASSID,1);
215   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
216   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERBINARY,&isbinary);CHKERRQ(ierr);
217   if (!isbinary) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Invalid viewer; open viewer with PetscViewerBinaryOpen()");
218 
219   ierr = PetscViewerBinaryRead(viewer,type,256,NULL,PETSC_CHAR);CHKERRQ(ierr);
220   ierr = TSAdaptSetType(adapt,type);CHKERRQ(ierr);
221   if (adapt->ops->load) {
222     ierr = (*adapt->ops->load)(adapt,viewer);CHKERRQ(ierr);
223   }
224   PetscFunctionReturn(0);
225 }
226 
227 #undef __FUNCT__
228 #define __FUNCT__ "TSAdaptView"
229 PetscErrorCode  TSAdaptView(TSAdapt adapt,PetscViewer viewer)
230 {
231   PetscErrorCode ierr;
232   PetscBool      iascii,isbinary;
233 
234   PetscFunctionBegin;
235   PetscValidHeaderSpecific(adapt,TSADAPT_CLASSID,1);
236   if (!viewer) {ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)adapt),&viewer);CHKERRQ(ierr);}
237   PetscValidHeaderSpecific(viewer,PETSC_VIEWER_CLASSID,2);
238   PetscCheckSameComm(adapt,1,viewer,2);
239   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
240   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERBINARY,&isbinary);CHKERRQ(ierr);
241   if (iascii) {
242     ierr = PetscObjectPrintClassNamePrefixType((PetscObject)adapt,viewer);CHKERRQ(ierr);
243     ierr = PetscViewerASCIIPrintf(viewer,"  number of candidates %D\n",adapt->candidates.n);CHKERRQ(ierr);
244     if (adapt->ops->view) {
245       ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
246       ierr = (*adapt->ops->view)(adapt,viewer);CHKERRQ(ierr);
247       ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
248     }
249   } else if (isbinary) {
250     char type[256];
251 
252     /* need to save FILE_CLASS_ID for adapt class */
253     ierr = PetscStrncpy(type,((PetscObject)adapt)->type_name,256);CHKERRQ(ierr);
254     ierr = PetscViewerBinaryWrite(viewer,type,256,PETSC_CHAR,PETSC_FALSE);CHKERRQ(ierr);
255   } else if (adapt->ops->view) {
256     ierr = (*adapt->ops->view)(adapt,viewer);CHKERRQ(ierr);
257   }
258   PetscFunctionReturn(0);
259 }
260 
261 #undef __FUNCT__
262 #define __FUNCT__ "TSAdaptReset"
263 /*@
264    TSAdaptReset - Resets a TSAdapt context.
265 
266    Collective on TS
267 
268    Input Parameter:
269 .  adapt - the TSAdapt context obtained from TSAdaptCreate()
270 
271    Level: developer
272 
273 .seealso: TSAdaptCreate(), TSAdaptDestroy()
274 @*/
275 PetscErrorCode  TSAdaptReset(TSAdapt adapt)
276 {
277   PetscErrorCode ierr;
278 
279   PetscFunctionBegin;
280   PetscValidHeaderSpecific(adapt,TSADAPT_CLASSID,1);
281   if (adapt->ops->reset) {ierr = (*adapt->ops->reset)(adapt);CHKERRQ(ierr);}
282   PetscFunctionReturn(0);
283 }
284 
285 #undef __FUNCT__
286 #define __FUNCT__ "TSAdaptDestroy"
287 PetscErrorCode  TSAdaptDestroy(TSAdapt *adapt)
288 {
289   PetscErrorCode ierr;
290 
291   PetscFunctionBegin;
292   if (!*adapt) PetscFunctionReturn(0);
293   PetscValidHeaderSpecific(*adapt,TSADAPT_CLASSID,1);
294   if (--((PetscObject)(*adapt))->refct > 0) {*adapt = NULL; PetscFunctionReturn(0);}
295 
296   ierr = TSAdaptReset(*adapt);CHKERRQ(ierr);
297 
298   if ((*adapt)->ops->destroy) {ierr = (*(*adapt)->ops->destroy)(*adapt);CHKERRQ(ierr);}
299   ierr = PetscViewerDestroy(&(*adapt)->monitor);CHKERRQ(ierr);
300   ierr = PetscHeaderDestroy(adapt);CHKERRQ(ierr);
301   PetscFunctionReturn(0);
302 }
303 
304 #undef __FUNCT__
305 #define __FUNCT__ "TSAdaptSetMonitor"
306 /*@
307    TSAdaptSetMonitor - Monitor the choices made by the adaptive controller
308 
309    Collective on TSAdapt
310 
311    Input Arguments:
312 +  adapt - adaptive controller context
313 -  flg - PETSC_TRUE to active a monitor, PETSC_FALSE to disable
314 
315    Level: intermediate
316 
317 .seealso: TSAdaptChoose()
318 @*/
319 PetscErrorCode TSAdaptSetMonitor(TSAdapt adapt,PetscBool flg)
320 {
321   PetscErrorCode ierr;
322 
323   PetscFunctionBegin;
324   PetscValidHeaderSpecific(adapt,TSADAPT_CLASSID,1);
325   PetscValidLogicalCollectiveBool(adapt,flg,2);
326   if (flg) {
327     if (!adapt->monitor) {ierr = PetscViewerASCIIOpen(PetscObjectComm((PetscObject)adapt),"stdout",&adapt->monitor);CHKERRQ(ierr);}
328   } else {
329     ierr = PetscViewerDestroy(&adapt->monitor);CHKERRQ(ierr);
330   }
331   PetscFunctionReturn(0);
332 }
333 
334 #undef __FUNCT__
335 #define __FUNCT__ "TSAdaptSetCheckStage"
336 /*@C
337    TSAdaptSetCheckStage - set a callback to check convergence for a stage
338 
339    Logically collective on TSAdapt
340 
341    Input Arguments:
342 +  adapt - adaptive controller context
343 -  func - stage check function
344 
345    Arguments of func:
346 $  PetscErrorCode func(TSAdapt adapt,TS ts,PetscBool *accept)
347 
348 +  adapt - adaptive controller context
349 .  ts - time stepping context
350 -  accept - pending choice of whether to accept, can be modified by this routine
351 
352    Level: advanced
353 
354 .seealso: TSAdaptChoose()
355 @*/
356 PetscErrorCode TSAdaptSetCheckStage(TSAdapt adapt,PetscErrorCode (*func)(TSAdapt,TS,PetscReal,Vec,PetscBool*))
357 {
358 
359   PetscFunctionBegin;
360   PetscValidHeaderSpecific(adapt,TSADAPT_CLASSID,1);
361   adapt->checkstage = func;
362   PetscFunctionReturn(0);
363 }
364 
365 #undef __FUNCT__
366 #define __FUNCT__ "TSAdaptSetStepLimits"
367 /*@
368    TSAdaptSetStepLimits - Set minimum and maximum step sizes to be considered by the controller
369 
370    Logically Collective
371 
372    Input Arguments:
373 +  adapt - time step adaptivity context, usually gotten with TSGetAdapt()
374 .  hmin - minimum time step
375 -  hmax - maximum time step
376 
377    Options Database Keys:
378 +  -ts_adapt_dt_min - minimum time step
379 -  -ts_adapt_dt_max - maximum time step
380 
381    Level: intermediate
382 
383 .seealso: TSAdapt
384 @*/
385 PetscErrorCode TSAdaptSetStepLimits(TSAdapt adapt,PetscReal hmin,PetscReal hmax)
386 {
387 
388   PetscFunctionBegin;
389   PetscValidHeaderSpecific(adapt,TSADAPT_CLASSID,1);
390   PetscValidLogicalCollectiveReal(adapt,hmin,2);
391   PetscValidLogicalCollectiveReal(adapt,hmax,3);
392   if (hmin != PETSC_DEFAULT && hmin < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Minimum time step %g must be non negative",(double)hmin);
393   if (hmax != PETSC_DEFAULT && hmax < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Minimum time step %g must be non negative",(double)hmax);
394   if (hmin != PETSC_DEFAULT) adapt->dt_min = hmin;
395   if (hmax != PETSC_DEFAULT) adapt->dt_max = hmax;
396 #if defined(PETSC_USE_DEBUG)
397   hmin = adapt->dt_min;
398   hmax = adapt->dt_max;
399   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);
400 #endif
401   PetscFunctionReturn(0);
402 }
403 
404 #undef __FUNCT__
405 #define __FUNCT__ "TSAdaptSetFromOptions"
406 /*
407    TSAdaptSetFromOptions - Sets various TSAdapt parameters from user options.
408 
409    Collective on TSAdapt
410 
411    Input Parameter:
412 .  adapt - the TSAdapt context
413 
414    Options Database Keys:
415 .  -ts_adapt_type <type> - basic
416 
417    Level: advanced
418 
419    Notes:
420    This function is automatically called by TSSetFromOptions()
421 
422 .keywords: TS, TSGetAdapt(), TSAdaptSetType()
423 
424 .seealso: TSGetType()
425 */
426 PetscErrorCode  TSAdaptSetFromOptions(PetscOptionItems *PetscOptionsObject,TSAdapt adapt)
427 {
428   PetscErrorCode ierr;
429   char           type[256] = TSADAPTBASIC;
430   PetscBool      set,flg;
431 
432   PetscFunctionBegin;
433   PetscValidHeaderSpecific(adapt,TSADAPT_CLASSID,1);
434   /* This should use PetscOptionsBegin() if/when this becomes an object used outside of TS, but currently this
435    * function can only be called from inside TSSetFromOptions()  */
436   ierr = PetscOptionsHead(PetscOptionsObject,"TS Adaptivity options");CHKERRQ(ierr);
437   ierr = PetscOptionsFList("-ts_adapt_type","Algorithm to use for adaptivity","TSAdaptSetType",TSAdaptList,
438                           ((PetscObject)adapt)->type_name ? ((PetscObject)adapt)->type_name : type,type,sizeof(type),&flg);CHKERRQ(ierr);
439   if (flg || !((PetscObject)adapt)->type_name) {
440     ierr = TSAdaptSetType(adapt,type);CHKERRQ(ierr);
441   }
442   ierr = PetscOptionsReal("-ts_adapt_dt_min","Minimum time step considered","TSAdaptSetStepLimits",adapt->dt_min,&adapt->dt_min,NULL);CHKERRQ(ierr);
443   ierr = PetscOptionsReal("-ts_adapt_dt_max","Maximum time step considered","TSAdaptSetStepLimits",adapt->dt_max,&adapt->dt_max,NULL);CHKERRQ(ierr);
444   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);
445   ierr = PetscOptionsBool("-ts_adapt_monitor","Print choices made by adaptive controller","TSAdaptSetMonitor",adapt->monitor ? PETSC_TRUE : PETSC_FALSE,&flg,&set);CHKERRQ(ierr);
446   ierr = PetscOptionsEnum("-ts_adapt_wnormtype","Type of norm computed for error estimation","",NormTypes,(PetscEnum)adapt->wnormtype,(PetscEnum*)&adapt->wnormtype,NULL);CHKERRQ(ierr);
447   if (adapt->wnormtype != NORM_2 && adapt->wnormtype != NORM_INFINITY) SETERRQ(PetscObjectComm((PetscObject)adapt),PETSC_ERR_SUP,"Only 2-norm and infinite norm supported");
448   if (set) {ierr = TSAdaptSetMonitor(adapt,flg);CHKERRQ(ierr);}
449   if (adapt->ops->setfromoptions) {ierr = (*adapt->ops->setfromoptions)(PetscOptionsObject,adapt);CHKERRQ(ierr);}
450   ierr = PetscOptionsTail();CHKERRQ(ierr);
451   PetscFunctionReturn(0);
452 }
453 
454 #undef __FUNCT__
455 #define __FUNCT__ "TSAdaptCandidatesClear"
456 /*@
457    TSAdaptCandidatesClear - clear any previously set candidate schemes
458 
459    Logically Collective
460 
461    Input Argument:
462 .  adapt - adaptive controller
463 
464    Level: developer
465 
466 .seealso: TSAdapt, TSAdaptCreate(), TSAdaptCandidateAdd(), TSAdaptChoose()
467 @*/
468 PetscErrorCode TSAdaptCandidatesClear(TSAdapt adapt)
469 {
470   PetscErrorCode ierr;
471 
472   PetscFunctionBegin;
473   PetscValidHeaderSpecific(adapt,TSADAPT_CLASSID,1);
474   ierr = PetscMemzero(&adapt->candidates,sizeof(adapt->candidates));CHKERRQ(ierr);
475   PetscFunctionReturn(0);
476 }
477 
478 #undef __FUNCT__
479 #define __FUNCT__ "TSAdaptCandidateAdd"
480 /*@C
481    TSAdaptCandidateAdd - add a candidate scheme for the adaptive controller to select from
482 
483    Logically Collective
484 
485    Input Arguments:
486 +  adapt - time step adaptivity context, obtained with TSGetAdapt() or TSAdaptCreate()
487 .  name - name of the candidate scheme to add
488 .  order - order of the candidate scheme
489 .  stageorder - stage order of the candidate scheme
490 .  ccfl - stability coefficient relative to explicit Euler, used for CFL constraints
491 .  cost - relative measure of the amount of work required for the candidate scheme
492 -  inuse - indicates that this scheme is the one currently in use, this flag can only be set for one scheme
493 
494    Note:
495    This routine is not available in Fortran.
496 
497    Level: developer
498 
499 .seealso: TSAdaptCandidatesClear(), TSAdaptChoose()
500 @*/
501 PetscErrorCode TSAdaptCandidateAdd(TSAdapt adapt,const char name[],PetscInt order,PetscInt stageorder,PetscReal ccfl,PetscReal cost,PetscBool inuse)
502 {
503   PetscInt c;
504 
505   PetscFunctionBegin;
506   PetscValidHeaderSpecific(adapt,TSADAPT_CLASSID,1);
507   if (order < 1) SETERRQ1(PetscObjectComm((PetscObject)adapt),PETSC_ERR_ARG_OUTOFRANGE,"Classical order %D must be a positive integer",order);
508   if (inuse) {
509     if (adapt->candidates.inuse_set) SETERRQ(PetscObjectComm((PetscObject)adapt),PETSC_ERR_ARG_WRONGSTATE,"Cannot set the inuse method twice, maybe forgot to call TSAdaptCandidatesClear()");
510     adapt->candidates.inuse_set = PETSC_TRUE;
511   }
512   /* first slot if this is the current scheme, otherwise the next available slot */
513   c = inuse ? 0 : !adapt->candidates.inuse_set + adapt->candidates.n;
514 
515   adapt->candidates.name[c]       = name;
516   adapt->candidates.order[c]      = order;
517   adapt->candidates.stageorder[c] = stageorder;
518   adapt->candidates.ccfl[c]       = ccfl;
519   adapt->candidates.cost[c]       = cost;
520   adapt->candidates.n++;
521   PetscFunctionReturn(0);
522 }
523 
524 #undef __FUNCT__
525 #define __FUNCT__ "TSAdaptCandidatesGet"
526 /*@C
527    TSAdaptCandidatesGet - Get the list of candidate orders of accuracy and cost
528 
529    Not Collective
530 
531    Input Arguments:
532 .  adapt - time step adaptivity context
533 
534    Output Arguments:
535 +  n - number of candidate schemes, always at least 1
536 .  order - the order of each candidate scheme
537 .  stageorder - the stage order of each candidate scheme
538 .  ccfl - the CFL coefficient of each scheme
539 -  cost - the relative cost of each scheme
540 
541    Level: developer
542 
543    Note:
544    The current scheme is always returned in the first slot
545 
546 .seealso: TSAdaptCandidatesClear(), TSAdaptCandidateAdd(), TSAdaptChoose()
547 @*/
548 PetscErrorCode TSAdaptCandidatesGet(TSAdapt adapt,PetscInt *n,const PetscInt **order,const PetscInt **stageorder,const PetscReal **ccfl,const PetscReal **cost)
549 {
550   PetscFunctionBegin;
551   PetscValidHeaderSpecific(adapt,TSADAPT_CLASSID,1);
552   if (n) *n = adapt->candidates.n;
553   if (order) *order = adapt->candidates.order;
554   if (stageorder) *stageorder = adapt->candidates.stageorder;
555   if (ccfl) *ccfl = adapt->candidates.ccfl;
556   if (cost) *cost = adapt->candidates.cost;
557   PetscFunctionReturn(0);
558 }
559 
560 #undef __FUNCT__
561 #define __FUNCT__ "TSAdaptChoose"
562 /*@C
563    TSAdaptChoose - choose which method and step size to use for the next step
564 
565    Logically Collective
566 
567    Input Arguments:
568 +  adapt - adaptive contoller
569 -  h - current step size
570 
571    Output Arguments:
572 +  next_sc - optional, scheme to use for the next step
573 .  next_h - step size to use for the next step
574 -  accept - PETSC_TRUE to accept the current step, PETSC_FALSE to repeat the current step with the new step size
575 
576    Note:
577    The input value of parameter accept is retained from the last time step, so it will be PETSC_FALSE if the step is
578    being retried after an initial rejection.
579 
580    Level: developer
581 
582 .seealso: TSAdapt, TSAdaptCandidatesClear(), TSAdaptCandidateAdd()
583 @*/
584 PetscErrorCode TSAdaptChoose(TSAdapt adapt,TS ts,PetscReal h,PetscInt *next_sc,PetscReal *next_h,PetscBool *accept)
585 {
586   PetscErrorCode ierr;
587   PetscInt       ncandidates = adapt->candidates.n;
588   PetscInt       scheme = 0;
589   PetscReal      wlte = -1.0;
590 
591   PetscFunctionBegin;
592   PetscValidHeaderSpecific(adapt,TSADAPT_CLASSID,1);
593   PetscValidHeaderSpecific(ts,TS_CLASSID,2);
594   if (next_sc) PetscValidIntPointer(next_sc,4);
595   PetscValidPointer(next_h,5);
596   PetscValidIntPointer(accept,6);
597   if (next_sc) *next_sc = 0;
598 
599   /* Do not mess with adaptivity while handling events*/
600   if (ts->event && ts->event->status != TSEVENT_NONE) {
601     *next_h = h;
602     *accept = PETSC_TRUE;
603     PetscFunctionReturn(0);
604   }
605 
606   ierr = (*adapt->ops->choose)(adapt,ts,h,&scheme,next_h,accept,&wlte);CHKERRQ(ierr);
607   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);
608   if (*next_h < 0) SETERRQ1(PetscObjectComm((PetscObject)adapt),PETSC_ERR_ARG_OUTOFRANGE,"Computed step size %g must be positive",(double)*next_h);
609   if (next_sc) *next_sc = scheme;
610 
611   if (*accept && ts->exact_final_time == TS_EXACTFINALTIME_MATCHSTEP) {
612     /* Reduce time step if it overshoots max time */
613     if (ts->ptime + ts->time_step + *next_h >= ts->max_time) {
614       PetscReal next_dt = ts->max_time - (ts->ptime + ts->time_step);
615       if (next_dt > PETSC_SMALL) *next_h = next_dt;
616       else ts->reason = TS_CONVERGED_TIME;
617     }
618   }
619 
620   if (adapt->monitor) {
621     const char *sc_name = (scheme < ncandidates) ? adapt->candidates.name[scheme] : "";
622     ierr = PetscViewerASCIIAddTab(adapt->monitor,((PetscObject)adapt)->tablevel);CHKERRQ(ierr);
623     if (wlte < 0) {
624       ierr = PetscViewerASCIIPrintf(adapt->monitor,"    TSAdapt '%s': step %3D %s t=%-11g+%10.3e family='%s' scheme=%D:'%s' dt=%-10.3e\n",((PetscObject)adapt)->type_name,ts->steps,*accept ? "accepted" : "rejected",(double)ts->ptime,(double)h,((PetscObject)ts)->type_name,scheme,sc_name,(double)*next_h);CHKERRQ(ierr);
625     } else {
626       ierr = PetscViewerASCIIPrintf(adapt->monitor,"    TSAdapt '%s': step %3D %s t=%-11g+%10.3e wlte=%5.3g family='%s' scheme=%D:'%s' dt=%-10.3e\n",((PetscObject)adapt)->type_name,ts->steps,*accept ? "accepted" : "rejected",(double)ts->ptime,(double)h,(double)wlte,((PetscObject)ts)->type_name,scheme,sc_name,(double)*next_h);CHKERRQ(ierr);
627     }
628     ierr = PetscViewerASCIISubtractTab(adapt->monitor,((PetscObject)adapt)->tablevel);CHKERRQ(ierr);
629   }
630   PetscFunctionReturn(0);
631 }
632 
633 #undef __FUNCT__
634 #define __FUNCT__ "TSAdaptCheckStage"
635 /*@
636    TSAdaptCheckStage - checks whether to accept a stage, (e.g. reject and change time step size if nonlinear solve fails)
637 
638    Collective
639 
640    Input Arguments:
641 +  adapt - adaptive controller context
642 .  ts - time stepper
643 .  t - Current simulation time
644 -  Y - Current solution vector
645 
646    Output Arguments:
647 .  accept - PETSC_TRUE to accept the stage, PETSC_FALSE to reject
648 
649    Level: developer
650 
651 .seealso:
652 @*/
653 PetscErrorCode TSAdaptCheckStage(TSAdapt adapt,TS ts,PetscReal t,Vec Y,PetscBool *accept)
654 {
655   PetscErrorCode      ierr;
656   SNESConvergedReason snesreason = SNES_CONVERGED_ITERATING;
657 
658   PetscFunctionBegin;
659   PetscValidHeaderSpecific(adapt,TSADAPT_CLASSID,1);
660   PetscValidHeaderSpecific(ts,TS_CLASSID,2);
661   PetscValidIntPointer(accept,3);
662 
663   if (ts->snes) {ierr = SNESGetConvergedReason(ts->snes,&snesreason);CHKERRQ(ierr);}
664   if (snesreason < 0) {
665     *accept = PETSC_FALSE;
666     if (++ts->num_snes_failures >= ts->max_snes_failures && ts->max_snes_failures > 0) {
667       ts->reason = TS_DIVERGED_NONLINEAR_SOLVE;
668       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);
669       if (adapt->monitor) {
670         ierr = PetscViewerASCIIAddTab(adapt->monitor,((PetscObject)adapt)->tablevel);CHKERRQ(ierr);
671         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);
672         ierr = PetscViewerASCIISubtractTab(adapt->monitor,((PetscObject)adapt)->tablevel);CHKERRQ(ierr);
673       }
674     }
675   } else {
676     *accept = PETSC_TRUE;
677     ierr = TSFunctionDomainError(ts,t,Y,accept);CHKERRQ(ierr);
678     if(*accept && adapt->checkstage) {
679       ierr = (*adapt->checkstage)(adapt,ts,t,Y,accept);CHKERRQ(ierr);
680     }
681   }
682 
683   if(!(*accept) && !ts->reason) {
684     PetscReal dt,new_dt;
685     ierr = TSGetTimeStep(ts,&dt);CHKERRQ(ierr);
686     new_dt = dt * adapt->scale_solve_failed;
687     ierr = TSSetTimeStep(ts,new_dt);CHKERRQ(ierr);
688     if (adapt->monitor) {
689       ierr = PetscViewerASCIIAddTab(adapt->monitor,((PetscObject)adapt)->tablevel);CHKERRQ(ierr);
690       ierr = PetscViewerASCIIPrintf(adapt->monitor,"    TSAdapt '%s': step %3D stage rejected t=%-11g+%10.3e retrying with dt=%-10.3e\n",((PetscObject)adapt)->type_name,ts->steps,(double)ts->ptime,(double)dt,(double)new_dt);CHKERRQ(ierr);
691       ierr = PetscViewerASCIISubtractTab(adapt->monitor,((PetscObject)adapt)->tablevel);CHKERRQ(ierr);
692     }
693   }
694   PetscFunctionReturn(0);
695 }
696 
697 #undef __FUNCT__
698 #define __FUNCT__ "TSAdaptCreate"
699 /*@
700   TSAdaptCreate - create an adaptive controller context for time stepping
701 
702   Collective on MPI_Comm
703 
704   Input Parameter:
705 . comm - The communicator
706 
707   Output Parameter:
708 . adapt - new TSAdapt object
709 
710   Level: developer
711 
712   Notes:
713   TSAdapt creation is handled by TS, so users should not need to call this function.
714 
715 .keywords: TSAdapt, create
716 .seealso: TSGetAdapt(), TSAdaptSetType(), TSAdaptDestroy()
717 @*/
718 PetscErrorCode  TSAdaptCreate(MPI_Comm comm,TSAdapt *inadapt)
719 {
720   PetscErrorCode ierr;
721   TSAdapt        adapt;
722 
723   PetscFunctionBegin;
724   PetscValidPointer(inadapt,1);
725   *inadapt = NULL;
726   ierr = TSAdaptInitializePackage();CHKERRQ(ierr);
727 
728   ierr = PetscHeaderCreate(adapt,TSADAPT_CLASSID,"TSAdapt","Time stepping adaptivity","TS",comm,TSAdaptDestroy,TSAdaptView);CHKERRQ(ierr);
729 
730   adapt->dt_min             = 1e-20;
731   adapt->dt_max             = 1e50;
732   adapt->scale_solve_failed = 0.25;
733   adapt->wnormtype          = NORM_2;
734   ierr = TSAdaptSetType(adapt,TSADAPTBASIC);CHKERRQ(ierr);
735 
736   *inadapt = adapt;
737   PetscFunctionReturn(0);
738 }
739