xref: /petsc/src/ts/adapt/interface/tsadapt.c (revision 3116ef58e11bc77b08297b681ddd79bc46c3f215)
1 
2 #include <private/tsimpl.h> /*I  "petscts.h" I*/
3 
4 static PetscFList TSAdaptList;
5 static PetscBool  TSAdaptPackageInitialized;
6 static PetscBool  TSAdaptRegisterAllCalled;
7 static PetscClassId TSADAPT_CLASSID;
8 
9 EXTERN_C_BEGIN
10 PetscErrorCode  TSAdaptCreate_Basic(TSAdapt);
11 PetscErrorCode  TSAdaptCreate_CFL(TSAdapt);
12 EXTERN_C_END
13 
14 #undef __FUNCT__
15 #define __FUNCT__ "TSAdaptRegister"
16 /*@C
17    TSAdaptRegister - see TSAdaptRegisterDynamic()
18 
19    Level: advanced
20 @*/
21 PetscErrorCode  TSAdaptRegister(const char sname[],const char path[],const char name[],PetscErrorCode (*function)(TSAdapt))
22 {
23   PetscErrorCode ierr;
24   char           fullname[PETSC_MAX_PATH_LEN];
25 
26   PetscFunctionBegin;
27   ierr = PetscFListConcat(path,name,fullname);CHKERRQ(ierr);
28   ierr = PetscFListAdd(&TSAdaptList,sname,fullname,(void(*)(void))function);CHKERRQ(ierr);
29   PetscFunctionReturn(0);
30 }
31 
32 #undef __FUNCT__
33 #define __FUNCT__ "TSAdaptRegisterAll"
34 /*@C
35   TSAdaptRegisterAll - Registers all of the adaptivity schemes in TSAdapt
36 
37   Not Collective
38 
39   Level: advanced
40 
41 .keywords: TSAdapt, register, all
42 
43 .seealso: TSAdaptRegisterDestroy()
44 @*/
45 PetscErrorCode  TSAdaptRegisterAll(const char path[])
46 {
47   PetscErrorCode ierr;
48 
49   PetscFunctionBegin;
50   ierr = TSAdaptRegisterDynamic(TSADAPTBASIC,path,"TSAdaptCreate_Basic",TSAdaptCreate_Basic);CHKERRQ(ierr);
51   ierr = TSAdaptRegisterDynamic(TSADAPTCFL,  path,"TSAdaptCreate_CFL",  TSAdaptCreate_CFL);CHKERRQ(ierr);
52   PetscFunctionReturn(0);
53 }
54 
55 #undef __FUNCT__
56 #define __FUNCT__ "TSAdaptFinalizePackage"
57 /*@C
58   TSFinalizePackage - This function destroys everything in the TS package. It is
59   called from PetscFinalize().
60 
61   Level: developer
62 
63 .keywords: Petsc, destroy, package
64 .seealso: PetscFinalize()
65 @*/
66 PetscErrorCode  TSAdaptFinalizePackage(void)
67 {
68   PetscFunctionBegin;
69   TSAdaptPackageInitialized = PETSC_FALSE;
70   TSAdaptRegisterAllCalled  = PETSC_FALSE;
71   TSAdaptList               = PETSC_NULL;
72   PetscFunctionReturn(0);
73 }
74 
75 #undef __FUNCT__
76 #define __FUNCT__ "TSAdaptInitializePackage"
77 /*@C
78   TSAdaptInitializePackage - This function initializes everything in the TSAdapt package. It is
79   called from PetscDLLibraryRegister() when using dynamic libraries, and on the first call to
80   TSCreate_GL() when using static libraries.
81 
82   Input Parameter:
83   path - The dynamic library path, or PETSC_NULL
84 
85   Level: developer
86 
87 .keywords: TSAdapt, initialize, package
88 .seealso: PetscInitialize()
89 @*/
90 PetscErrorCode  TSAdaptInitializePackage(const char path[])
91 {
92   PetscErrorCode ierr;
93 
94   PetscFunctionBegin;
95   if (TSAdaptPackageInitialized) PetscFunctionReturn(0);
96   TSAdaptPackageInitialized = PETSC_TRUE;
97   ierr = PetscClassIdRegister("TSAdapt",&TSADAPT_CLASSID);CHKERRQ(ierr);
98   ierr = TSAdaptRegisterAll(path);CHKERRQ(ierr);
99   ierr = PetscRegisterFinalize(TSAdaptFinalizePackage);CHKERRQ(ierr);
100   PetscFunctionReturn(0);
101 }
102 
103 #undef __FUNCT__
104 #define __FUNCT__ "TSAdaptRegisterDestroy"
105 /*@C
106    TSAdaptRegisterDestroy - Frees the list of adaptivity schemes that were registered by TSAdaptRegister()/TSAdaptRegisterDynamic().
107 
108    Not Collective
109 
110    Level: advanced
111 
112 .keywords: TSAdapt, register, destroy
113 .seealso: TSAdaptRegister(), TSAdaptRegisterAll(), TSAdaptRegisterDynamic()
114 @*/
115 PetscErrorCode  TSAdaptRegisterDestroy(void)
116 {
117   PetscErrorCode ierr;
118 
119   PetscFunctionBegin;
120   ierr = PetscFListDestroy(&TSAdaptList);CHKERRQ(ierr);
121   TSAdaptRegisterAllCalled = PETSC_FALSE;
122   PetscFunctionReturn(0);
123 }
124 
125 
126 #undef __FUNCT__
127 #define __FUNCT__ "TSAdaptSetType"
128 PetscErrorCode  TSAdaptSetType(TSAdapt adapt,const TSAdaptType type)
129 {
130   PetscErrorCode ierr,(*r)(TSAdapt);
131 
132   PetscFunctionBegin;
133   ierr = PetscFListFind(TSAdaptList,((PetscObject)adapt)->comm,type,PETSC_TRUE,(void(**)(void))&r);CHKERRQ(ierr);
134   if (!r) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_UNKNOWN_TYPE,"Unknown TSAdapt type \"%s\" given",type);
135   if (((PetscObject)adapt)->type_name) {ierr = (*adapt->ops->destroy)(adapt);CHKERRQ(ierr);}
136   ierr = (*r)(adapt);CHKERRQ(ierr);
137   ierr = PetscObjectChangeTypeName((PetscObject)adapt,type);CHKERRQ(ierr);
138   PetscFunctionReturn(0);
139 }
140 
141 #undef __FUNCT__
142 #define __FUNCT__ "TSAdaptSetOptionsPrefix"
143 PetscErrorCode  TSAdaptSetOptionsPrefix(TSAdapt adapt,const char prefix[])
144 {
145   PetscErrorCode ierr;
146 
147   PetscFunctionBegin;
148   ierr = PetscObjectSetOptionsPrefix((PetscObject)adapt,prefix);CHKERRQ(ierr);
149   PetscFunctionReturn(0);
150 }
151 
152 #undef __FUNCT__
153 #define __FUNCT__ "TSAdaptView"
154 PetscErrorCode  TSAdaptView(TSAdapt adapt,PetscViewer viewer)
155 {
156   PetscErrorCode ierr;
157   PetscBool      iascii;
158 
159   PetscFunctionBegin;
160   ierr = PetscTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
161   if (iascii) {
162     ierr = PetscObjectPrintClassNamePrefixType((PetscObject)adapt,viewer,"TSAdapt Object");CHKERRQ(ierr);
163     ierr = PetscViewerASCIIPrintf(viewer,"number of candidates %D\n",adapt->candidates.n);CHKERRQ(ierr);
164     if (adapt->ops->view) {
165       ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
166       ierr = (*adapt->ops->view)(adapt,viewer);CHKERRQ(ierr);
167       ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
168     }
169   } else {
170     SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Viewer type %s not supported",((PetscObject)viewer)->type_name);
171   }
172   PetscFunctionReturn(0);
173 }
174 
175 #undef __FUNCT__
176 #define __FUNCT__ "TSAdaptDestroy"
177 PetscErrorCode  TSAdaptDestroy(TSAdapt *adapt)
178 {
179   PetscErrorCode ierr;
180 
181   PetscFunctionBegin;
182   if (!*adapt) PetscFunctionReturn(0);
183   PetscValidHeaderSpecific(*adapt,TSADAPT_CLASSID,1);
184   if (--((PetscObject)(*adapt))->refct > 0) {*adapt = 0; PetscFunctionReturn(0);}
185   if ((*adapt)->ops->destroy) {ierr = (*(*adapt)->ops->destroy)(*adapt);CHKERRQ(ierr);}
186   ierr = PetscViewerDestroy(&(*adapt)->monitor);CHKERRQ(ierr);
187   ierr = PetscHeaderDestroy(adapt);CHKERRQ(ierr);
188   PetscFunctionReturn(0);
189 }
190 
191 #undef __FUNCT__
192 #define __FUNCT__ "TSAdaptSetMonitor"
193 /*@
194    TSAdaptSetMonitor - Monitor the choices made by the adaptive controller
195 
196    Collective on TSAdapt
197 
198    Input Arguments:
199 +  adapt - adaptive controller context
200 -  flg - PETSC_TRUE to active a monitor, PETSC_FALSE to disable
201 
202    Level: intermediate
203 
204 .seealso: TSAdaptChoose()
205 @*/
206 PetscErrorCode TSAdaptSetMonitor(TSAdapt adapt,PetscBool flg)
207 {
208   PetscErrorCode ierr;
209 
210   PetscFunctionBegin;
211   if (flg) {
212     if (!adapt->monitor) {ierr = PetscViewerASCIIOpen(((PetscObject)adapt)->comm,"stdout",&adapt->monitor);CHKERRQ(ierr);}
213   } else {
214     ierr = PetscViewerDestroy(&adapt->monitor);CHKERRQ(ierr);
215   }
216   PetscFunctionReturn(0);
217 }
218 
219 #undef __FUNCT__
220 #define __FUNCT__ "TSAdaptSetStepLimits"
221 /*@
222    TSAdaptSetStepLimits - Set minimum and maximum step sizes to be considered by the controller
223 
224    Logically Collective
225 
226    Input Arguments:
227 +  adapt - time step adaptivity context, usually gotten with TSGetAdapt()
228 .  hmin - minimum time step
229 -  hmax - maximum time step
230 
231    Options Database Keys:
232 +  -ts_adapt_dt_min - minimum time step
233 -  -ts_adapt_dt_max - maximum time step
234 
235    Level: intermediate
236 
237 .seealso: TSAdapt
238 @*/
239 PetscErrorCode TSAdaptSetStepLimits(TSAdapt adapt,PetscReal hmin,PetscReal hmax)
240 {
241 
242   PetscFunctionBegin;
243   if (hmin != PETSC_DECIDE) adapt->dt_min = hmin;
244   if (hmax != PETSC_DECIDE) adapt->dt_max = hmax;
245   PetscFunctionReturn(0);
246 }
247 
248 #undef __FUNCT__
249 #define __FUNCT__ "TSAdaptSetFromOptions"
250 /*@
251    TSAdaptSetFromOptions - Sets various TSAdapt parameters from user options.
252 
253    Collective on TSAdapt
254 
255    Input Parameter:
256 .  adapt - the TSAdapt context
257 
258    Options Database Keys:
259 .  -ts_adapt_type <type> - basic
260 
261    Level: advanced
262 
263    Notes:
264    This function is automatically called by TSSetFromOptions()
265 
266 .keywords: TS, TSGetAdapt(), TSAdaptSetType()
267 
268 .seealso: TSGetType()
269 @*/
270 PetscErrorCode  TSAdaptSetFromOptions(TSAdapt adapt)
271 {
272   PetscErrorCode ierr;
273   char           type[256] = TSADAPTBASIC;
274   PetscBool      set,flg;
275 
276   PetscFunctionBegin;
277   /* This should use PetscOptionsBegin() if/when this becomes an object used outside of TS, but currently this
278   * function can only be called from inside TSSetFromOptions_GL()  */
279   ierr = PetscOptionsHead("TS Adaptivity options");CHKERRQ(ierr);
280   ierr = PetscOptionsList("-ts_adapt_type","Algorithm to use for adaptivity","TSAdaptSetType",TSAdaptList,
281                           ((PetscObject)adapt)->type_name?((PetscObject)adapt)->type_name:type,type,sizeof type,&flg);CHKERRQ(ierr);
282   if (flg || !((PetscObject)adapt)->type_name) {
283     ierr = TSAdaptSetType(adapt,type);CHKERRQ(ierr);
284   }
285   if (adapt->ops->setfromoptions) {ierr = (*adapt->ops->setfromoptions)(adapt);CHKERRQ(ierr);}
286   ierr = PetscOptionsReal("-ts_adapt_dt_min","Minimum time step considered","TSAdaptSetStepLimits",adapt->dt_min,&adapt->dt_min,PETSC_NULL);CHKERRQ(ierr);
287   ierr = PetscOptionsReal("-ts_adapt_dt_max","Maximum time step considered","TSAdaptSetStepLimits",adapt->dt_max,&adapt->dt_max,PETSC_NULL);CHKERRQ(ierr);
288   ierr = PetscOptionsBool("-ts_adapt_monitor","Print choices made by adaptive controller","TSAdaptSetMonitor",adapt->monitor ? PETSC_TRUE : PETSC_FALSE,&flg,&set);CHKERRQ(ierr);
289   if (set) {ierr = TSAdaptSetMonitor(adapt,flg);CHKERRQ(ierr);}
290   ierr = PetscOptionsTail();CHKERRQ(ierr);
291   PetscFunctionReturn(0);
292 }
293 
294 #undef __FUNCT__
295 #define __FUNCT__ "TSAdaptCandidatesClear"
296 /*@
297    TSAdaptCandidatesClear - clear any previously set candidate schemes
298 
299    Logically Collective
300 
301    Input Argument:
302 .  adapt - adaptive controller
303 
304    Level: developer
305 
306 .seealso: TSAdapt, TSAdaptCreate(), TSAdaptCandidateAdd(), TSAdaptChoose()
307 @*/
308 PetscErrorCode TSAdaptCandidatesClear(TSAdapt adapt)
309 {
310   PetscErrorCode ierr;
311 
312   PetscFunctionBegin;
313   ierr = PetscMemzero(&adapt->candidates,sizeof(adapt->candidates));CHKERRQ(ierr);
314   PetscFunctionReturn(0);
315 }
316 
317 #undef __FUNCT__
318 #define __FUNCT__ "TSAdaptCandidateAdd"
319 /*@C
320    TSAdaptCandidateAdd - add a candidate scheme for the adaptive controller to select from
321 
322    Logically Collective
323 
324    Input Arguments:
325 +  adapt - time step adaptivity context, obtained with TSGetAdapt() or TSAdaptCreate()
326 .  name - name of the candidate scheme to add
327 .  order - order of the candidate scheme
328 .  stageorder - stage order of the candidate scheme
329 .  ccfl - stability coefficient relative to explicit Euler, used for CFL constraints
330 .  cost - relative measure of the amount of work required for the candidate scheme
331 -  inuse - indicates that this scheme is the one currently in use, this flag can only be set for one scheme
332 
333    Note:
334    This routine is not available in Fortran.
335 
336    Level: developer
337 
338 .seealso: TSAdaptCandidatesClear(), TSAdaptChoose()
339 @*/
340 PetscErrorCode TSAdaptCandidateAdd(TSAdapt adapt,const char name[],PetscInt order,PetscInt stageorder,PetscReal ccfl,PetscReal cost,PetscBool inuse)
341 {
342   PetscInt c;
343 
344   PetscFunctionBegin;
345   PetscValidHeaderSpecific(adapt,TSADAPT_CLASSID,1);
346   if (order < 1) SETERRQ1(((PetscObject)adapt)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Classical order %D must be a positive integer",order);
347   if (inuse) {
348     if (adapt->candidates.inuse_set) SETERRQ(((PetscObject)adapt)->comm,PETSC_ERR_ARG_WRONGSTATE,"Cannot set the inuse method twice, maybe forgot to call TSAdaptCandidatesClear()");
349     adapt->candidates.inuse_set = PETSC_TRUE;
350   }
351   /* first slot if this is the current scheme, otherwise the next available slot */
352   c = inuse ? 0 : !adapt->candidates.inuse_set + adapt->candidates.n;
353   adapt->candidates.name[c]         = name;
354   adapt->candidates.order[c]        = order;
355   adapt->candidates.stageorder[c]   = stageorder;
356   adapt->candidates.ccfl[c]         = ccfl;
357   adapt->candidates.cost[c]         = cost;
358   adapt->candidates.n++;
359   PetscFunctionReturn(0);
360 }
361 
362 #undef __FUNCT__
363 #define __FUNCT__ "TSAdaptCandidatesGet"
364 /*@C
365    TSAdaptCandidatesGet - Get the list of candidate orders of accuracy and cost
366 
367    Not Collective
368 
369    Input Arguments:
370 .  adapt - time step adaptivity context
371 
372    Output Arguments:
373 +  n - number of candidate schemes, always at least 1
374 .  order - the order of each candidate scheme
375 .  stageorder - the stage order of each candidate scheme
376 .  ccfl - the CFL coefficient of each scheme
377 -  cost - the relative cost of each scheme
378 
379    Level: developer
380 
381    Note:
382    The current scheme is always returned in the first slot
383 
384 .seealso: TSAdaptCandidatesClear(), TSAdaptCandidateAdd(), TSAdaptChoose()
385 @*/
386 PetscErrorCode TSAdaptCandidatesGet(TSAdapt adapt,PetscInt *n,const PetscInt **order,const PetscInt **stageorder,const PetscReal **ccfl,const PetscReal **cost)
387 {
388   PetscFunctionBegin;
389   PetscValidHeaderSpecific(adapt,TSADAPT_CLASSID,1);
390   if (n) *n = adapt->candidates.n;
391   if (order) *order = adapt->candidates.order;
392   if (stageorder) *stageorder = adapt->candidates.stageorder;
393   if (ccfl) *ccfl = adapt->candidates.ccfl;
394   if (cost) *cost = adapt->candidates.cost;
395   PetscFunctionReturn(0);
396 }
397 
398 #undef __FUNCT__
399 #define __FUNCT__ "TSAdaptChoose"
400 /*@C
401    TSAdaptChoose - choose which method and step size to use for the next step
402 
403    Logically Collective
404 
405    Input Arguments:
406 +  adapt - adaptive contoller
407 -  h - current step size
408 
409    Output Arguments:
410 +  next_sc - scheme to use for the next step
411 .  next_h - step size to use for the next step
412 -  accept - PETSC_TRUE to accept the current step, PETSC_FALSE to repeat the current step with the new step size
413 
414    Note:
415    The input value of parameter accept is retained from the last time step, so it will be PETSC_FALSE if the step is
416    being retried after an initial rejection.
417 
418    Level: developer
419 
420 .seealso: TSAdapt, TSAdaptCandidatesClear(), TSAdaptCandidateAdd()
421 @*/
422 PetscErrorCode TSAdaptChoose(TSAdapt adapt,TS ts,PetscReal h,PetscInt *next_sc,PetscReal *next_h,PetscBool *accept)
423 {
424   PetscErrorCode ierr;
425 
426   PetscFunctionBegin;
427   PetscValidHeaderSpecific(adapt,TSADAPT_CLASSID,1);
428   PetscValidHeaderSpecific(ts,TS_CLASSID,2);
429   PetscValidIntPointer(next_sc,4);
430   PetscValidPointer(next_h,5);
431   PetscValidIntPointer(accept,6);
432   if (adapt->candidates.n < 1) SETERRQ1(((PetscObject)adapt)->comm,PETSC_ERR_ARG_WRONGSTATE,"%D candidates have been registered",adapt->candidates.n);
433   if (!adapt->candidates.inuse_set) SETERRQ1(((PetscObject)adapt)->comm,PETSC_ERR_ARG_WRONGSTATE,"The current in-use scheme is not among the %D candidates",adapt->candidates.n);
434   ierr = (*adapt->ops->choose)(adapt,ts,h,next_sc,next_h,accept);CHKERRQ(ierr);
435   if (*next_sc < 0 || adapt->candidates.n <= *next_sc) SETERRQ2(((PetscObject)adapt)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Chosen scheme %D not in valid range 0..%D",*next_sc,adapt->candidates.n-1);
436   if (!(*next_h > 0.)) SETERRQ1(((PetscObject)adapt)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Computed step size %G must be positive",*next_h);
437 
438   if (adapt->monitor) {
439     ierr = PetscViewerASCIIAddTab(adapt->monitor,((PetscObject)adapt)->tablevel);CHKERRQ(ierr);
440     ierr = PetscViewerASCIIPrintf(adapt->monitor,"    TSAdapt '%s': step %s  family='%s' scheme=%D:'%s' dt=%G\n",((PetscObject)adapt)->type_name,accept?"accepted":"rejected",((PetscObject)ts)->type_name,*next_sc,adapt->candidates.name[*next_sc],*next_h);CHKERRQ(ierr);
441     ierr = PetscViewerASCIISubtractTab(adapt->monitor,((PetscObject)adapt)->tablevel);CHKERRQ(ierr);
442   }
443   PetscFunctionReturn(0);
444 }
445 
446 #undef __FUNCT__
447 #define __FUNCT__ "TSAdaptCreate"
448 /*@
449   TSAdaptCreate - create an adaptive controller context for time stepping
450 
451   Collective on MPI_Comm
452 
453   Input Parameter:
454 . comm - The communicator
455 
456   Output Parameter:
457 . adapt - new TSAdapt object
458 
459   Level: developer
460 
461   Notes:
462   TSAdapt creation is handled by TS, so users should not need to call this function.
463 
464 .keywords: TSAdapt, create
465 .seealso: TSGetAdapt(), TSAdaptSetType(), TSAdaptDestroy()
466 @*/
467 PetscErrorCode  TSAdaptCreate(MPI_Comm comm,TSAdapt *inadapt)
468 {
469   PetscErrorCode ierr;
470   TSAdapt adapt;
471 
472   PetscFunctionBegin;
473   *inadapt = 0;
474   ierr = PetscHeaderCreate(adapt,_p_TSAdapt,struct _TSAdaptOps,TSADAPT_CLASSID,0,"TSAdapt","General Linear adaptivity","TS",comm,TSAdaptDestroy,TSAdaptView);CHKERRQ(ierr);
475 
476   adapt->dt_min = 1e-20;
477   adapt->dt_max = 1e50;
478 
479   *inadapt = adapt;
480   PetscFunctionReturn(0);
481 }
482