xref: /petsc/src/sys/objects/aoptions.c (revision 4df4a32cb8db0b7b88394c85cd73c68458309a1d)
1 /*
2    Implements the higher-level options database querying methods. These are self-documenting and can attach at runtime to
3    GUI code to display the options and get values from the users.
4 
5 */
6 
7 #include <petsc/private/petscimpl.h> /*I  "petscsys.h"   I*/
8 #include <petscviewer.h>
9 
10 static const char *ManSection(const char *str)
11 {
12   return str ? str : "None";
13 }
14 
15 static const char *Prefix(const char *str)
16 {
17   return str ? str : "";
18 }
19 
20 static int ShouldPrintHelp(const PetscOptionItems *opts)
21 {
22   return opts->printhelp && opts->count == 1 && !opts->alreadyprinted;
23 }
24 
25 /*
26     Keep a linked list of options that have been posted and we are waiting for
27    user selection. See the manual page for PetscOptionsBegin()
28 
29     Eventually we'll attach this beast to a MPI_Comm
30 */
31 
32 /*
33     Handles setting up the data structure in a call to PetscOptionsBegin()
34 */
35 PetscErrorCode PetscOptionsBegin_Private(PetscOptionItems *PetscOptionsObject, MPI_Comm comm, const char prefix[], const char title[], const char mansec[])
36 {
37   PetscFunctionBegin;
38   if (prefix) PetscAssertPointer(prefix, 3);
39   PetscAssertPointer(title, 4);
40   if (mansec) PetscAssertPointer(mansec, 5);
41   if (!PetscOptionsObject->alreadyprinted) {
42     if (!PetscOptionsHelpPrintedSingleton) PetscCall(PetscOptionsHelpPrintedCreate(&PetscOptionsHelpPrintedSingleton));
43     PetscCall(PetscOptionsHelpPrintedCheck(PetscOptionsHelpPrintedSingleton, prefix, title, &PetscOptionsObject->alreadyprinted));
44   }
45   PetscOptionsObject->next          = NULL;
46   PetscOptionsObject->comm          = comm;
47   PetscOptionsObject->changedmethod = PETSC_FALSE;
48 
49   PetscCall(PetscStrallocpy(prefix, &PetscOptionsObject->prefix));
50   PetscCall(PetscStrallocpy(title, &PetscOptionsObject->title));
51 
52   PetscCall(PetscOptionsHasHelp(PetscOptionsObject->options, &PetscOptionsObject->printhelp));
53   if (ShouldPrintHelp(PetscOptionsObject)) PetscCall((*PetscHelpPrintf)(comm, "----------------------------------------\n%s:\n", title));
54   PetscFunctionReturn(PETSC_SUCCESS);
55 }
56 
57 /*
58     Handles setting up the data structure in a call to PetscObjectOptionsBegin()
59 */
60 PetscErrorCode PetscObjectOptionsBegin_Private(PetscObject obj, PetscOptionItems *PetscOptionsObject)
61 {
62   char      title[256];
63   PetscBool flg;
64 
65   PetscFunctionBegin;
66   PetscAssertPointer(PetscOptionsObject, 2);
67   PetscValidHeader(obj, 1);
68   PetscOptionsObject->object         = obj;
69   PetscOptionsObject->alreadyprinted = obj->optionsprinted;
70 
71   PetscCall(PetscStrcmp(obj->description, obj->class_name, &flg));
72   if (flg) PetscCall(PetscSNPrintf(title, sizeof(title), "%s options", obj->class_name));
73   else PetscCall(PetscSNPrintf(title, sizeof(title), "%s (%s) options", obj->description, obj->class_name));
74   PetscCall(PetscOptionsBegin_Private(PetscOptionsObject, obj->comm, obj->prefix, title, obj->mansec));
75   PetscFunctionReturn(PETSC_SUCCESS);
76 }
77 
78 /*
79      Handles adding another option to the list of options within this particular PetscOptionsBegin() PetscOptionsEnd()
80 */
81 static PetscErrorCode PetscOptionItemCreate_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], PetscOptionType t, PetscOptionItem *amsopt)
82 {
83   PetscBool valid;
84 
85   PetscFunctionBegin;
86   PetscCall(PetscOptionsValidKey(opt, &valid));
87   PetscCheck(valid, PETSC_COMM_WORLD, PETSC_ERR_ARG_INCOMP, "The option '%s' is not a valid key", opt);
88 
89   PetscCall(PetscNew(amsopt));
90   (*amsopt)->next = NULL;
91   (*amsopt)->set  = PETSC_FALSE;
92   (*amsopt)->type = t;
93   (*amsopt)->data = NULL;
94 
95   PetscCall(PetscStrallocpy(text, &(*amsopt)->text));
96   PetscCall(PetscStrallocpy(opt, &(*amsopt)->option));
97   PetscCall(PetscStrallocpy(man, &(*amsopt)->man));
98 
99   {
100     PetscOptionItem cur = PetscOptionsObject->next;
101 
102     while (cur->next) cur = cur->next;
103     cur->next = *amsopt;
104   }
105   PetscFunctionReturn(PETSC_SUCCESS);
106 }
107 
108 /*
109     This is needed because certain strings may be freed by SAWs, hence we cannot use PetscStrallocpy()
110 */
111 static PetscErrorCode PetscStrdup(const char s[], char *t[])
112 {
113   char *tmp = NULL;
114 
115   PetscFunctionBegin;
116   if (s) {
117     size_t len;
118 
119     PetscCall(PetscStrlen(s, &len));
120     tmp = (char *)malloc((len + 1) * sizeof(*tmp));
121     PetscCheck(tmp, PETSC_COMM_SELF, PETSC_ERR_MEM, "No memory to duplicate string");
122     PetscCall(PetscArraycpy(tmp, s, len + 1));
123   }
124   *t = tmp;
125   PetscFunctionReturn(PETSC_SUCCESS);
126 }
127 
128 #if defined(PETSC_HAVE_SAWS)
129   #include <petscviewersaws.h>
130 
131 static int count = 0;
132 
133 PetscErrorCode PetscOptionsSAWsDestroy(void)
134 {
135   PetscFunctionBegin;
136   PetscFunctionReturn(PETSC_SUCCESS);
137 }
138 
139 static const char *OptionsHeader = "<head>\n"
140                                    "<script type=\"text/javascript\" src=\"https://www.mcs.anl.gov/research/projects/saws/js/jquery-1.9.1.js\"></script>\n"
141                                    "<script type=\"text/javascript\" src=\"https://www.mcs.anl.gov/research/projects/saws/js/SAWs.js\"></script>\n"
142                                    "<script type=\"text/javascript\" src=\"js/PETSc.js\"></script>\n"
143                                    "<script>\n"
144                                    "jQuery(document).ready(function() {\n"
145                                    "PETSc.getAndDisplayDirectory(null,\"#variablesInfo\")\n"
146                                    "})\n"
147                                    "</script>\n"
148                                    "</head>\n";
149 
150 /*  Determines the size and style of the scroll region where PETSc options selectable from users are displayed */
151 static const char *OptionsBodyBottom = "<div id=\"variablesInfo\" style=\"background-color:lightblue;height:auto;max-height:500px;overflow:scroll;\"></div>\n<br>\n</body>";
152 
153 /*
154     PetscOptionsSAWsInput - Presents all the PETSc Options processed by the program so the user may change them at runtime using the SAWs
155 
156     Bugs:
157 +    All processes must traverse through the exact same set of option queries due to the call to PetscScanString()
158 .    Internal strings have arbitrary length and string copies are not checked that they fit into string space
159 -    Only works for PetscInt == int, PetscReal == double etc
160 
161 */
162 static PetscErrorCode PetscOptionsSAWsInput(PetscOptionItems *PetscOptionsObject)
163 {
164   PetscOptionItem next     = PetscOptionsObject->next;
165   static int      mancount = 0;
166   char            options[16];
167   PetscBool       changedmethod = PETSC_FALSE;
168   PetscBool       stopasking    = PETSC_FALSE;
169   char            manname[16], textname[16];
170   char            dir[1024];
171 
172   PetscFunctionBegin;
173   /* the next line is a bug, this will only work if all processors are here, the comm passed in is ignored!!! */
174   PetscCall(PetscSNPrintf(options, PETSC_STATIC_ARRAY_LENGTH(options), "Options_%d", count++));
175 
176   PetscOptionsObject->pprefix = PetscOptionsObject->prefix; /* SAWs will change this, so cannot pass prefix directly */
177 
178   PetscCall(PetscSNPrintf(dir, 1024, "/PETSc/Options/%s", "_title"));
179   PetscCallSAWs(SAWs_Register, (dir, &PetscOptionsObject->title, 1, SAWs_READ, SAWs_STRING));
180   PetscCall(PetscSNPrintf(dir, 1024, "/PETSc/Options/%s", "prefix"));
181   PetscCallSAWs(SAWs_Register, (dir, &PetscOptionsObject->pprefix, 1, SAWs_READ, SAWs_STRING));
182   PetscCallSAWs(SAWs_Register, ("/PETSc/Options/ChangedMethod", &changedmethod, 1, SAWs_WRITE, SAWs_BOOLEAN));
183   PetscCallSAWs(SAWs_Register, ("/PETSc/Options/StopAsking", &stopasking, 1, SAWs_WRITE, SAWs_BOOLEAN));
184 
185   while (next) {
186     PetscCall(PetscSNPrintf(manname, PETSC_STATIC_ARRAY_LENGTH(manname), "_man_%d", mancount));
187     PetscCall(PetscSNPrintf(dir, 1024, "/PETSc/Options/%s", manname));
188     PetscCallSAWs(SAWs_Register, (dir, &next->man, 1, SAWs_READ, SAWs_STRING));
189     PetscCall(PetscSNPrintf(textname, PETSC_STATIC_ARRAY_LENGTH(textname), "_text_%d", mancount++));
190     PetscCall(PetscSNPrintf(dir, 1024, "/PETSc/Options/%s", textname));
191     PetscCallSAWs(SAWs_Register, (dir, &next->text, 1, SAWs_READ, SAWs_STRING));
192 
193     switch (next->type) {
194     case OPTION_HEAD:
195       break;
196     case OPTION_INT_ARRAY:
197       PetscCall(PetscSNPrintf(dir, 1024, "/PETSc/Options/%s", next->option));
198       PetscCallSAWs(SAWs_Register, (dir, next->data, next->arraylength, SAWs_WRITE, SAWs_INT));
199       break;
200     case OPTION_REAL_ARRAY:
201       PetscCall(PetscSNPrintf(dir, 1024, "/PETSc/Options/%s", next->option));
202       PetscCallSAWs(SAWs_Register, (dir, next->data, next->arraylength, SAWs_WRITE, SAWs_DOUBLE));
203       break;
204     case OPTION_INT:
205       PetscCall(PetscSNPrintf(dir, 1024, "/PETSc/Options/%s", next->option));
206       PetscCallSAWs(SAWs_Register, (dir, next->data, 1, SAWs_WRITE, SAWs_INT));
207       break;
208     case OPTION_REAL:
209       PetscCall(PetscSNPrintf(dir, 1024, "/PETSc/Options/%s", next->option));
210       PetscCallSAWs(SAWs_Register, (dir, next->data, 1, SAWs_WRITE, SAWs_DOUBLE));
211       break;
212     case OPTION_BOOL:
213       PetscCall(PetscSNPrintf(dir, 1024, "/PETSc/Options/%s", next->option));
214       PetscCallSAWs(SAWs_Register, (dir, next->data, 1, SAWs_WRITE, SAWs_BOOLEAN));
215       break;
216     case OPTION_BOOL_ARRAY:
217       PetscCall(PetscSNPrintf(dir, 1024, "/PETSc/Options/%s", next->option));
218       PetscCallSAWs(SAWs_Register, (dir, next->data, next->arraylength, SAWs_WRITE, SAWs_BOOLEAN));
219       break;
220     case OPTION_STRING:
221       PetscCall(PetscSNPrintf(dir, 1024, "/PETSc/Options/%s", next->option));
222       PetscCallSAWs(SAWs_Register, (dir, &next->data, 1, SAWs_WRITE, SAWs_STRING));
223       break;
224     case OPTION_STRING_ARRAY:
225       PetscCall(PetscSNPrintf(dir, 1024, "/PETSc/Options/%s", next->option));
226       PetscCallSAWs(SAWs_Register, (dir, next->data, next->arraylength, SAWs_WRITE, SAWs_STRING));
227       break;
228     case OPTION_FLIST: {
229       PetscInt ntext;
230       PetscCall(PetscSNPrintf(dir, 1024, "/PETSc/Options/%s", next->option));
231       PetscCallSAWs(SAWs_Register, (dir, &next->data, 1, SAWs_WRITE, SAWs_STRING));
232       PetscCall(PetscFunctionListGet(next->flist, (const char ***)&next->edata, &ntext));
233       PetscCallSAWs(SAWs_Set_Legal_Variable_Values, (dir, ntext, next->edata));
234     } break;
235     case OPTION_ELIST: {
236       PetscInt ntext = next->nlist;
237       PetscCall(PetscSNPrintf(dir, 1024, "/PETSc/Options/%s", next->option));
238       PetscCallSAWs(SAWs_Register, (dir, &next->data, 1, SAWs_WRITE, SAWs_STRING));
239       PetscCall(PetscMalloc1(ntext + 1, (char ***)&next->edata));
240       PetscCall(PetscMemcpy(next->edata, next->list, ntext * sizeof(char *)));
241       PetscCallSAWs(SAWs_Set_Legal_Variable_Values, (dir, ntext, next->edata));
242     } break;
243     default:
244       break;
245     }
246     next = next->next;
247   }
248 
249   /* wait until accessor has unlocked the memory */
250   PetscCallSAWs(SAWs_Push_Header, ("index.html", OptionsHeader));
251   PetscCallSAWs(SAWs_Push_Body, ("index.html", 2, OptionsBodyBottom));
252   PetscCall(PetscSAWsBlock());
253   PetscCallSAWs(SAWs_Pop_Header, ("index.html"));
254   PetscCallSAWs(SAWs_Pop_Body, ("index.html", 2));
255 
256   /* determine if any values have been set in GUI */
257   next = PetscOptionsObject->next;
258   while (next) {
259     PetscCall(PetscSNPrintf(dir, 1024, "/PETSc/Options/%s", next->option));
260     PetscCallSAWs(SAWs_Selected, (dir, (int *)&next->set));
261     next = next->next;
262   }
263 
264   /* reset counter to -2; this updates the screen with the new options for the selected method */
265   if (changedmethod) PetscOptionsObject->count = -2;
266 
267   if (stopasking) {
268     PetscOptionsPublish       = PETSC_FALSE;
269     PetscOptionsObject->count = 0; //do not ask for same thing again
270   }
271 
272   PetscCallSAWs(SAWs_Delete, ("/PETSc/Options"));
273   PetscFunctionReturn(PETSC_SUCCESS);
274 }
275 #else
276 /*
277     PetscScanString -  Gets user input via stdin from process and broadcasts to all processes
278 
279     Collective
280 
281    Input Parameters:
282 +     commm - communicator for the broadcast, must be PETSC_COMM_WORLD
283 .     n - length of the string, must be the same on all processes
284 -     str - location to store input
285 
286     Bugs:
287 .   Assumes process 0 of the given communicator has access to stdin
288 
289 */
290 static PetscErrorCode PetscScanString(MPI_Comm comm, size_t n, char str[])
291 {
292   PetscMPIInt rank, nm;
293 
294   PetscFunctionBegin;
295   PetscCallMPI(MPI_Comm_rank(comm, &rank));
296   if (rank == 0) {
297     char   c = (char)getchar();
298     size_t i = 0;
299 
300     while (c != '\n' && i < n - 1) {
301       str[i++] = c;
302       c        = (char)getchar();
303     }
304     str[i] = '\0';
305   }
306   PetscCall(PetscMPIIntCast(n, &nm));
307   PetscCallMPI(MPI_Bcast(str, nm, MPI_CHAR, 0, comm));
308   PetscFunctionReturn(PETSC_SUCCESS);
309 }
310 
311 /*
312   PetscOptionsGetFromTextInput - Presents all the PETSc Options processed by the program so the user may change them at runtime
313 
314   Notes:
315   this isn't really practical, it is just to demonstrate the principle
316 
317   A carriage return indicates no change from the default; but this like -ksp_monitor <stdout>  the default is actually not stdout the default
318   is to do nothing so to get it to use stdout you need to type stdout. This is kind of bug?
319 
320   Bugs:
321 +    All processes must traverse through the exact same set of option queries due to the call to PetscScanString()
322 .    Internal strings have arbitrary length and string copies are not checked that they fit into string space
323 -    Only works for PetscInt == int, PetscReal == double etc
324 
325   Developer Notes:
326   Normally the GUI that presents the options the user and retrieves the values would be running in a different
327   address space and communicating with the PETSc program
328 
329 */
330 static PetscErrorCode PetscOptionsGetFromTextInput(PetscOptionItems *PetscOptionsObject)
331 {
332   PetscOptionItem next = PetscOptionsObject->next;
333   char            str[512];
334   PetscBool       bid;
335   PetscReal       ir, *valr;
336   PetscInt       *vald;
337 
338   PetscFunctionBegin;
339   PetscCall((*PetscPrintf)(PETSC_COMM_WORLD, "%s --------------------\n", PetscOptionsObject->title));
340   while (next) {
341     switch (next->type) {
342     case OPTION_HEAD:
343       break;
344     case OPTION_INT_ARRAY:
345       PetscCall(PetscPrintf(PETSC_COMM_WORLD, "-%s%s: <", PetscOptionsObject->prefix ? PetscOptionsObject->prefix : "", next->option + 1));
346       vald = (PetscInt *)next->data;
347       for (PetscInt i = 0; i < next->arraylength; i++) {
348         PetscCall(PetscPrintf(PETSC_COMM_WORLD, "%" PetscInt_FMT, vald[i]));
349         if (i < next->arraylength - 1) PetscCall(PetscPrintf(PETSC_COMM_WORLD, ","));
350       }
351       PetscCall(PetscPrintf(PETSC_COMM_WORLD, ">: %s (%s) ", next->text, next->man));
352       PetscCall(PetscScanString(PETSC_COMM_WORLD, 512, str));
353       if (str[0]) {
354         PetscToken token;
355         PetscInt   n = 0, nmax = next->arraylength, *dvalue = (PetscInt *)next->data, start, end;
356         size_t     i, len;
357         char      *value;
358         PetscBool  foundrange;
359 
360         next->set = PETSC_TRUE;
361         value     = str;
362         PetscCall(PetscTokenCreate(value, ',', &token));
363         PetscCall(PetscTokenFind(token, &value));
364         while (n < nmax) {
365           if (!value) break;
366 
367           /* look for form  d-D where d and D are integers */
368           foundrange = PETSC_FALSE;
369           PetscCall(PetscStrlen(value, &len));
370           if (value[0] == '-') i = 2;
371           else i = 1;
372           for (; i < len; i++) {
373             if (value[i] == '-') {
374               PetscCheck(i != len - 1, PETSC_COMM_SELF, PETSC_ERR_USER, "Error in %" PetscInt_FMT "-th array entry %s", n, value);
375               value[i] = 0;
376               PetscCall(PetscOptionsStringToInt(value, &start));
377               PetscCall(PetscOptionsStringToInt(value + i + 1, &end));
378               PetscCheck(end > start, PETSC_COMM_SELF, PETSC_ERR_USER, "Error in %" PetscInt_FMT "-th array entry, %s-%s cannot have decreasing list", n, value, value + i + 1);
379               PetscCheck(n + end - start - 1 < nmax, PETSC_COMM_SELF, PETSC_ERR_USER, "Error in %" PetscInt_FMT "-th array entry, not enough space in left in array (%" PetscInt_FMT ") to contain entire range from %" PetscInt_FMT " to %" PetscInt_FMT, n, nmax - n, start, end);
380               for (; start < end; start++) {
381                 *dvalue = start;
382                 dvalue++;
383                 n++;
384               }
385               foundrange = PETSC_TRUE;
386               break;
387             }
388           }
389           if (!foundrange) {
390             PetscCall(PetscOptionsStringToInt(value, dvalue));
391             dvalue++;
392             n++;
393           }
394           PetscCall(PetscTokenFind(token, &value));
395         }
396         PetscCall(PetscTokenDestroy(&token));
397       }
398       break;
399     case OPTION_REAL_ARRAY:
400       PetscCall(PetscPrintf(PETSC_COMM_WORLD, "-%s%s: <", PetscOptionsObject->prefix ? PetscOptionsObject->prefix : "", next->option + 1));
401       valr = (PetscReal *)next->data;
402       for (PetscInt i = 0; i < next->arraylength; i++) {
403         PetscCall(PetscPrintf(PETSC_COMM_WORLD, "%g", (double)valr[i]));
404         if (i < next->arraylength - 1) PetscCall(PetscPrintf(PETSC_COMM_WORLD, ","));
405       }
406       PetscCall(PetscPrintf(PETSC_COMM_WORLD, ">: %s (%s) ", next->text, next->man));
407       PetscCall(PetscScanString(PETSC_COMM_WORLD, 512, str));
408       if (str[0]) {
409         PetscToken token;
410         PetscInt   n = 0, nmax = next->arraylength;
411         PetscReal *dvalue = (PetscReal *)next->data;
412         char      *value;
413 
414         next->set = PETSC_TRUE;
415         value     = str;
416         PetscCall(PetscTokenCreate(value, ',', &token));
417         PetscCall(PetscTokenFind(token, &value));
418         while (n < nmax) {
419           if (!value) break;
420           PetscCall(PetscOptionsStringToReal(value, dvalue));
421           dvalue++;
422           n++;
423           PetscCall(PetscTokenFind(token, &value));
424         }
425         PetscCall(PetscTokenDestroy(&token));
426       }
427       break;
428     case OPTION_INT:
429       PetscCall(PetscPrintf(PETSC_COMM_WORLD, "-%s%s: <%d>: %s (%s) ", PetscOptionsObject->prefix ? PetscOptionsObject->prefix : "", next->option + 1, *(int *)next->data, next->text, next->man));
430       PetscCall(PetscScanString(PETSC_COMM_WORLD, 512, str));
431       if (str[0]) {
432   #if defined(PETSC_SIZEOF_LONG_LONG)
433         long long lid;
434         sscanf(str, "%lld", &lid);
435         PetscCheck(lid <= PETSC_INT_MAX && lid >= PETSC_INT_MIN, PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE, "Argument: -%s%s %lld", PetscOptionsObject->prefix ? PetscOptionsObject->prefix : "", next->option + 1, lid);
436   #else
437         long lid;
438         sscanf(str, "%ld", &lid);
439         PetscCheck(lid <= PETSC_INT_MAX && lid >= PETSC_INT_MIN, PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE, "Argument: -%s%s %ld", PetscOptionsObject->prefix ? PetscOptionsObject->prefix : "", next->option + 1, lid);
440   #endif
441 
442         next->set                 = PETSC_TRUE;
443         *((PetscInt *)next->data) = (PetscInt)lid;
444       }
445       break;
446     case OPTION_REAL:
447       PetscCall(PetscPrintf(PETSC_COMM_WORLD, "-%s%s: <%g>: %s (%s) ", PetscOptionsObject->prefix ? PetscOptionsObject->prefix : "", next->option + 1, *(double *)next->data, next->text, next->man));
448       PetscCall(PetscScanString(PETSC_COMM_WORLD, 512, str));
449       if (str[0]) {
450   #if defined(PETSC_USE_REAL_SINGLE)
451         sscanf(str, "%e", &ir);
452   #elif defined(PETSC_USE_REAL___FP16)
453         float irtemp;
454         sscanf(str, "%e", &irtemp);
455         ir = irtemp;
456   #elif defined(PETSC_USE_REAL_DOUBLE)
457         sscanf(str, "%le", &ir);
458   #elif defined(PETSC_USE_REAL___FLOAT128)
459         ir = strtoflt128(str, 0);
460   #else
461         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Unknown scalar type");
462   #endif
463         next->set                  = PETSC_TRUE;
464         *((PetscReal *)next->data) = ir;
465       }
466       break;
467     case OPTION_BOOL:
468       PetscCall(PetscPrintf(PETSC_COMM_WORLD, "-%s%s: <%s>: %s (%s) ", PetscOptionsObject->prefix ? PetscOptionsObject->prefix : "", next->option + 1, *(PetscBool *)next->data ? "true" : "false", next->text, next->man));
469       PetscCall(PetscScanString(PETSC_COMM_WORLD, 512, str));
470       if (str[0]) {
471         PetscCall(PetscOptionsStringToBool(str, &bid));
472         next->set                  = PETSC_TRUE;
473         *((PetscBool *)next->data) = bid;
474       }
475       break;
476     case OPTION_STRING:
477       PetscCall(PetscPrintf(PETSC_COMM_WORLD, "-%s%s: <%s>: %s (%s) ", PetscOptionsObject->prefix ? PetscOptionsObject->prefix : "", next->option + 1, (char *)next->data, next->text, next->man));
478       PetscCall(PetscScanString(PETSC_COMM_WORLD, 512, str));
479       if (str[0]) {
480         next->set = PETSC_TRUE;
481         /* must use system malloc since SAWs may free this */
482         PetscCall(PetscStrdup(str, (char **)&next->data));
483       }
484       break;
485     case OPTION_FLIST:
486       PetscCall(PetscFunctionListPrintTypes(PETSC_COMM_WORLD, stdout, PetscOptionsObject->prefix, next->option, next->text, next->man, next->flist, (char *)next->data, (char *)next->data));
487       PetscCall(PetscScanString(PETSC_COMM_WORLD, 512, str));
488       if (str[0]) {
489         PetscOptionsObject->changedmethod = PETSC_TRUE;
490         next->set                         = PETSC_TRUE;
491         /* must use system malloc since SAWs may free this */
492         PetscCall(PetscStrdup(str, (char **)&next->data));
493       }
494       break;
495     default:
496       break;
497     }
498     next = next->next;
499   }
500   PetscFunctionReturn(PETSC_SUCCESS);
501 }
502 #endif
503 
504 PetscErrorCode PetscOptionsEnd_Private(PetscOptionItems *PetscOptionsObject)
505 {
506   PetscOptionItem next, last;
507 
508   PetscFunctionBegin;
509   if (PetscOptionsObject->next) {
510     if (!PetscOptionsObject->count) {
511 #if defined(PETSC_HAVE_SAWS)
512       PetscCall(PetscOptionsSAWsInput(PetscOptionsObject));
513 #else
514       PetscCall(PetscOptionsGetFromTextInput(PetscOptionsObject));
515 #endif
516     }
517   }
518 
519   PetscCall(PetscFree(PetscOptionsObject->title));
520 
521   /* reset counter to -2; this updates the screen with the new options for the selected method */
522   if (PetscOptionsObject->changedmethod) PetscOptionsObject->count = -2;
523   /* reset alreadyprinted flag */
524   PetscOptionsObject->alreadyprinted = PETSC_FALSE;
525   if (PetscOptionsObject->object) PetscOptionsObject->object->optionsprinted = PETSC_TRUE;
526   PetscOptionsObject->object = NULL;
527 
528   while ((next = PetscOptionsObject->next)) {
529     const PetscOptionType type        = next->type;
530     const size_t          arraylength = next->arraylength;
531     void                 *data        = next->data;
532 
533     if (next->set) {
534       char option[256], value[1024], tmp[32];
535 
536       if (PetscOptionsObject->prefix) {
537         PetscCall(PetscStrncpy(option, "-", sizeof(option)));
538         PetscCall(PetscStrlcat(option, PetscOptionsObject->prefix, sizeof(option)));
539         PetscCall(PetscStrlcat(option, next->option + 1, sizeof(option)));
540       } else {
541         PetscCall(PetscStrncpy(option, next->option, sizeof(option)));
542       }
543 
544       switch (type) {
545       case OPTION_HEAD:
546         break;
547       case OPTION_INT_ARRAY:
548         PetscCall(PetscSNPrintf(value, PETSC_STATIC_ARRAY_LENGTH(value), "%" PetscInt_FMT, ((PetscInt *)data)[0]));
549         for (size_t j = 1; j < arraylength; ++j) {
550           PetscCall(PetscSNPrintf(tmp, PETSC_STATIC_ARRAY_LENGTH(tmp), "%" PetscInt_FMT, ((PetscInt *)data)[j]));
551           PetscCall(PetscStrlcat(value, ",", sizeof(value)));
552           PetscCall(PetscStrlcat(value, tmp, sizeof(value)));
553         }
554         break;
555       case OPTION_INT:
556         PetscCall(PetscSNPrintf(value, PETSC_STATIC_ARRAY_LENGTH(value), "%" PetscInt_FMT, *(PetscInt *)data));
557         break;
558       case OPTION_REAL:
559         PetscCall(PetscSNPrintf(value, PETSC_STATIC_ARRAY_LENGTH(value), "%g", (double)*(PetscReal *)data));
560         break;
561       case OPTION_REAL_ARRAY:
562         PetscCall(PetscSNPrintf(value, PETSC_STATIC_ARRAY_LENGTH(value), "%g", (double)((PetscReal *)data)[0]));
563         for (size_t j = 1; j < arraylength; ++j) {
564           PetscCall(PetscSNPrintf(tmp, PETSC_STATIC_ARRAY_LENGTH(tmp), "%g", (double)((PetscReal *)data)[j]));
565           PetscCall(PetscStrlcat(value, ",", sizeof(value)));
566           PetscCall(PetscStrlcat(value, tmp, sizeof(value)));
567         }
568         break;
569       case OPTION_SCALAR_ARRAY:
570         PetscCall(PetscSNPrintf(value, PETSC_STATIC_ARRAY_LENGTH(value), "%g+%gi", (double)PetscRealPart(((PetscScalar *)data)[0]), (double)PetscImaginaryPart(((PetscScalar *)data)[0])));
571         for (size_t j = 1; j < arraylength; ++j) {
572           PetscCall(PetscSNPrintf(tmp, PETSC_STATIC_ARRAY_LENGTH(tmp), "%g+%gi", (double)PetscRealPart(((PetscScalar *)data)[j]), (double)PetscImaginaryPart(((PetscScalar *)data)[j])));
573           PetscCall(PetscStrlcat(value, ",", sizeof(value)));
574           PetscCall(PetscStrlcat(value, tmp, sizeof(value)));
575         }
576         break;
577       case OPTION_BOOL:
578         PetscCall(PetscSNPrintf(value, PETSC_STATIC_ARRAY_LENGTH(value), "%d", *(int *)data));
579         break;
580       case OPTION_BOOL_ARRAY:
581         PetscCall(PetscSNPrintf(value, PETSC_STATIC_ARRAY_LENGTH(value), "%d", (int)((PetscBool *)data)[0]));
582         for (size_t j = 1; j < arraylength; ++j) {
583           PetscCall(PetscSNPrintf(tmp, PETSC_STATIC_ARRAY_LENGTH(tmp), "%d", (int)((PetscBool *)data)[j]));
584           PetscCall(PetscStrlcat(value, ",", sizeof(value)));
585           PetscCall(PetscStrlcat(value, tmp, sizeof(value)));
586         }
587         break;
588       case OPTION_FLIST: // fall-through
589       case OPTION_ELIST: // fall-through
590       case OPTION_STRING:
591         PetscCall(PetscStrncpy(value, (char *)data, sizeof(value)));
592         break;
593       case OPTION_STRING_ARRAY:
594         PetscCall(PetscSNPrintf(value, PETSC_STATIC_ARRAY_LENGTH(value), "%s", ((char **)data)[0]));
595         for (size_t j = 1; j < arraylength; j++) {
596           PetscCall(PetscSNPrintf(tmp, PETSC_STATIC_ARRAY_LENGTH(tmp), "%s", ((char **)data)[j]));
597           PetscCall(PetscStrlcat(value, ",", sizeof(value)));
598           PetscCall(PetscStrlcat(value, tmp, sizeof(value)));
599         }
600         break;
601       }
602       PetscCall(PetscOptionsSetValue(PetscOptionsObject->options, option, value));
603     }
604     if (type == OPTION_ELIST) PetscCall(PetscStrNArrayDestroy(next->nlist, (char ***)&next->list));
605     PetscCall(PetscFree(next->text));
606     PetscCall(PetscFree(next->option));
607     PetscCall(PetscFree(next->man));
608     PetscCall(PetscFree(next->edata));
609 
610     if (type == OPTION_STRING || type == OPTION_FLIST || type == OPTION_ELIST) {
611       free(data);
612     } else {
613       // use next->data instead of data because PetscFree() sets it to NULL
614       PetscCall(PetscFree(next->data));
615     }
616 
617     last                     = next;
618     PetscOptionsObject->next = next->next;
619     PetscCall(PetscFree(last));
620   }
621   PetscCall(PetscFree(PetscOptionsObject->prefix));
622   PetscOptionsObject->next = NULL;
623   PetscFunctionReturn(PETSC_SUCCESS);
624 }
625 
626 static PetscErrorCode GetListLength(const char *const *list, PetscInt *len)
627 {
628   PetscInt retlen = 0;
629 
630   PetscFunctionBegin;
631   PetscAssertPointer(len, 2);
632   while (list[retlen]) {
633     PetscAssertPointer(list[retlen], 1);
634     PetscCheck(++retlen < 50, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "List argument appears to be wrong or have more than 50 entries");
635   }
636   PetscCheck(retlen > 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "List argument must have at least 2 entries: typename and type prefix");
637   /* drop item name and prefix*/
638   *len = retlen - 2;
639   PetscFunctionReturn(PETSC_SUCCESS);
640 }
641 
642 PetscErrorCode PetscOptionsEnum_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], const char *const *list, PetscEnum currentvalue, PetscEnum *value, PetscBool *set)
643 {
644   PetscInt  ntext = 0;
645   PetscInt  tval;
646   PetscBool tflg;
647 
648   PetscFunctionBegin;
649   PetscAssertPointer(opt, 2);
650   PetscAssertPointer(list, 5);
651   PetscAssertPointer(value, 7);
652   if (set) PetscAssertPointer(set, 8);
653   PetscCall(GetListLength(list, &ntext));
654   PetscCall(PetscOptionsEList_Private(PetscOptionsObject, opt, text, man, list, ntext, list[currentvalue], &tval, &tflg));
655   /* with PETSC_USE_64BIT_INDICES sizeof(PetscInt) != sizeof(PetscEnum) */
656   if (tflg) *value = (PetscEnum)tval;
657   if (set) *set = tflg;
658   PetscFunctionReturn(PETSC_SUCCESS);
659 }
660 
661 PetscErrorCode PetscOptionsEnumArray_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], const char *const *list, PetscEnum value[], PetscInt *n, PetscBool *set)
662 {
663   PetscInt    nlist  = 0;
664   const char *prefix = PetscOptionsObject->prefix;
665 
666   PetscFunctionBegin;
667   PetscAssertPointer(opt, 2);
668   PetscAssertPointer(list, 5);
669   PetscAssertPointer(value, 6);
670   PetscAssertPointer(n, 7);
671   PetscCheck(*n > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "n (%" PetscInt_FMT ") must be > 0", *n);
672   if (set) PetscAssertPointer(set, 8);
673   PetscCall(GetListLength(list, &nlist));
674   PetscCall(PetscOptionsGetEnumArray(PetscOptionsObject->options, prefix, opt, list, value, n, set));
675   if (ShouldPrintHelp(PetscOptionsObject)) {
676     const MPI_Comm comm = PetscOptionsObject->comm;
677     const PetscInt nv   = *n;
678 
679     PetscCall((*PetscHelpPrintf)(comm, "  -%s%s: <%s", Prefix(prefix), opt + 1, list[value[0]]));
680     for (PetscInt i = 1; i < nv; ++i) PetscCall((*PetscHelpPrintf)(comm, ",%s", list[value[i]]));
681     PetscCall((*PetscHelpPrintf)(comm, ">: %s (choose from)", text));
682     for (PetscInt i = 0; i < nlist; ++i) PetscCall((*PetscHelpPrintf)(comm, " %s", list[i]));
683     PetscCall((*PetscHelpPrintf)(comm, " (%s)\n", ManSection(man)));
684   }
685   PetscFunctionReturn(PETSC_SUCCESS);
686 }
687 
688 PetscErrorCode PetscOptionsInt_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], PetscInt currentvalue, PetscInt *value, PetscBool *set, PetscInt lb, PetscInt ub)
689 {
690   const char        *prefix  = PetscOptionsObject->prefix;
691   const PetscOptions options = PetscOptionsObject->options;
692   PetscBool          wasset;
693 
694   PetscFunctionBegin;
695   PetscAssertPointer(opt, 2);
696   PetscAssertPointer(value, 6);
697   if (set) PetscAssertPointer(set, 7);
698   PetscCheck(currentvalue >= lb, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Current value %" PetscInt_FMT " less than allowed bound %" PetscInt_FMT, currentvalue, lb);
699   PetscCheck(currentvalue <= ub, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Current value %" PetscInt_FMT " greater than allowed bound %" PetscInt_FMT, currentvalue, ub);
700   if (!PetscOptionsObject->count) {
701     PetscOptionItem amsopt;
702 
703     PetscCall(PetscOptionItemCreate_Private(PetscOptionsObject, opt, text, man, OPTION_INT, &amsopt));
704     PetscCall(PetscMalloc(sizeof(PetscInt), &amsopt->data));
705     *(PetscInt *)amsopt->data = currentvalue;
706 
707     PetscCall(PetscOptionsGetInt(options, prefix, opt, &currentvalue, &wasset));
708     if (wasset) *(PetscInt *)amsopt->data = currentvalue;
709   }
710   PetscCall(PetscOptionsGetInt(options, prefix, opt, value, &wasset));
711   PetscCheck(!wasset || *value >= lb, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Newly set value %" PetscInt_FMT " less than allowed bound %" PetscInt_FMT, *value, lb);
712   PetscCheck(!wasset || *value <= ub, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Newly set value %" PetscInt_FMT " greater than allowed bound %" PetscInt_FMT, *value, ub);
713   if (set) *set = wasset;
714   if (ShouldPrintHelp(PetscOptionsObject)) {
715     PetscCall((*PetscHelpPrintf)(PetscOptionsObject->comm, "  -%s%s: <now %" PetscInt_FMT " : formerly %" PetscInt_FMT ">: %s (%s)\n", Prefix(prefix), opt + 1, wasset ? *value : currentvalue, currentvalue, text, ManSection(man)));
716   }
717   PetscFunctionReturn(PETSC_SUCCESS);
718 }
719 
720 PetscErrorCode PetscOptionsMPIInt_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], PetscMPIInt currentvalue, PetscMPIInt *value, PetscBool *set, PetscMPIInt lb, PetscMPIInt ub)
721 {
722   const char        *prefix  = PetscOptionsObject->prefix;
723   const PetscOptions options = PetscOptionsObject->options;
724   PetscBool          wasset;
725 
726   PetscFunctionBegin;
727   PetscAssertPointer(opt, 2);
728   PetscAssertPointer(value, 6);
729   if (set) PetscAssertPointer(set, 7);
730   PetscCheck(currentvalue >= lb, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Current value %d less than allowed bound %d", currentvalue, lb);
731   PetscCheck(currentvalue <= ub, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Current value %d greater than allowed bound %d", currentvalue, ub);
732   if (!PetscOptionsObject->count) {
733     PetscOptionItem amsopt;
734 
735     PetscCall(PetscOptionItemCreate_Private(PetscOptionsObject, opt, text, man, OPTION_INT, &amsopt));
736     PetscCall(PetscMalloc(sizeof(PetscInt), &amsopt->data));
737     *(PetscMPIInt *)amsopt->data = currentvalue;
738 
739     PetscCall(PetscOptionsGetMPIInt(options, prefix, opt, &currentvalue, &wasset));
740     if (wasset) *(PetscMPIInt *)amsopt->data = currentvalue;
741   }
742   PetscCall(PetscOptionsGetMPIInt(options, prefix, opt, value, &wasset));
743   PetscCheck(!wasset || *value >= lb, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Newly set value %d less than allowed bound %d", *value, lb);
744   PetscCheck(!wasset || *value <= ub, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Newly set value %d greater than allowed bound %d", *value, ub);
745   if (set) *set = wasset;
746   if (ShouldPrintHelp(PetscOptionsObject)) { PetscCall((*PetscHelpPrintf)(PetscOptionsObject->comm, "  -%s%s: <now %d : formerly %d>: %s (%s)\n", Prefix(prefix), opt + 1, wasset ? *value : currentvalue, currentvalue, text, ManSection(man))); }
747   PetscFunctionReturn(PETSC_SUCCESS);
748 }
749 
750 PetscErrorCode PetscOptionsString_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], const char currentvalue[], char value[], size_t len, PetscBool *set)
751 {
752   const char *prefix = PetscOptionsObject->prefix;
753   PetscBool   lset;
754 
755   PetscFunctionBegin;
756   PetscAssertPointer(opt, 2);
757   PetscAssertPointer(value, 6);
758   if (set) PetscAssertPointer(set, 8);
759   if (!PetscOptionsObject->count) {
760     PetscOptionItem amsopt;
761 
762     PetscCall(PetscOptionItemCreate_Private(PetscOptionsObject, opt, text, man, OPTION_STRING, &amsopt));
763     /* must use system malloc since SAWs may free this */
764     PetscCall(PetscStrdup(currentvalue ? currentvalue : "", (char **)&amsopt->data));
765   }
766   PetscCall(PetscOptionsGetString(PetscOptionsObject->options, prefix, opt, value, len, &lset));
767   if (set) *set = lset;
768   if (ShouldPrintHelp(PetscOptionsObject)) PetscCall((*PetscHelpPrintf)(PetscOptionsObject->comm, "  -%s%s: <now %s : formerly %s>: %s (%s)\n", Prefix(prefix), opt + 1, lset ? value : currentvalue, currentvalue, text, ManSection(man)));
769   PetscFunctionReturn(PETSC_SUCCESS);
770 }
771 
772 PetscErrorCode PetscOptionsReal_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], PetscReal currentvalue, PetscReal *value, PetscBool *set, PetscReal lb, PetscReal ub)
773 {
774   const char        *prefix  = PetscOptionsObject->prefix;
775   const PetscOptions options = PetscOptionsObject->options;
776   PetscBool          wasset;
777 
778   PetscFunctionBegin;
779   PetscAssertPointer(opt, 2);
780   PetscAssertPointer(value, 6);
781   if (set) PetscAssertPointer(set, 7);
782   PetscCheck(currentvalue >= lb, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Current value %g less than allowed bound %g", (double)currentvalue, (double)lb);
783   PetscCheck(currentvalue <= ub, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Current value %g greater than allowed bound %g", (double)currentvalue, (double)ub);
784   if (!PetscOptionsObject->count) {
785     PetscOptionItem amsopt;
786 
787     PetscCall(PetscOptionItemCreate_Private(PetscOptionsObject, opt, text, man, OPTION_REAL, &amsopt));
788     PetscCall(PetscMalloc(sizeof(PetscReal), &amsopt->data));
789     *(PetscReal *)amsopt->data = currentvalue;
790 
791     PetscCall(PetscOptionsGetReal(options, prefix, opt, &currentvalue, &wasset));
792     if (wasset) *(PetscReal *)amsopt->data = currentvalue;
793   }
794   PetscCall(PetscOptionsGetReal(PetscOptionsObject->options, prefix, opt, value, &wasset));
795   PetscCheck(!wasset || *value >= lb, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Newly set value %g less than allowed bound %g", (double)*value, (double)lb);
796   PetscCheck(!wasset || *value <= ub, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Newly set value %g greater than allowed bound %g", (double)*value, (double)ub);
797   if (set) *set = wasset;
798   if (ShouldPrintHelp(PetscOptionsObject)) {
799     PetscCall((*PetscHelpPrintf)(PetscOptionsObject->comm, "  -%s%s: <now %g : formerly %g>: %s (%s)\n", Prefix(prefix), opt + 1, wasset ? (double)*value : (double)currentvalue, (double)currentvalue, text, ManSection(man)));
800   }
801   PetscFunctionReturn(PETSC_SUCCESS);
802 }
803 
804 PetscErrorCode PetscOptionsScalar_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], PetscScalar currentvalue, PetscScalar *value, PetscBool *set)
805 {
806   PetscFunctionBegin;
807 #if !defined(PETSC_USE_COMPLEX)
808   PetscCall(PetscOptionsReal(opt, text, man, currentvalue, value, set));
809 #else
810   PetscCall(PetscOptionsGetScalar(PetscOptionsObject->options, PetscOptionsObject->prefix, opt, value, set));
811 #endif
812   PetscFunctionReturn(PETSC_SUCCESS);
813 }
814 
815 PetscErrorCode PetscOptionsName_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], PetscBool *flg)
816 {
817   const char *prefix = PetscOptionsObject->prefix;
818 
819   PetscFunctionBegin;
820   PetscAssertPointer(opt, 2);
821   PetscAssertPointer(flg, 5);
822   if (!PetscOptionsObject->count) {
823     PetscOptionItem amsopt;
824 
825     PetscCall(PetscOptionItemCreate_Private(PetscOptionsObject, opt, text, man, OPTION_BOOL, &amsopt));
826     PetscCall(PetscMalloc(sizeof(PetscBool), &amsopt->data));
827 
828     *(PetscBool *)amsopt->data = PETSC_FALSE;
829   }
830   PetscCall(PetscOptionsHasName(PetscOptionsObject->options, prefix, opt, flg));
831   if (ShouldPrintHelp(PetscOptionsObject)) PetscCall((*PetscHelpPrintf)(PetscOptionsObject->comm, "  -%s%s: %s (%s)\n", Prefix(prefix), opt + 1, text, ManSection(man)));
832   PetscFunctionReturn(PETSC_SUCCESS);
833 }
834 
835 PetscErrorCode PetscOptionsFList_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char ltext[], const char man[], PetscFunctionList list, const char currentvalue[], char value[], size_t len, PetscBool *set)
836 {
837   const char *prefix = PetscOptionsObject->prefix;
838   PetscBool   lset;
839 
840   PetscFunctionBegin;
841   PetscAssertPointer(opt, 2);
842   PetscAssertPointer(value, 7);
843   if (set) PetscAssertPointer(set, 9);
844   if (!PetscOptionsObject->count) {
845     PetscOptionItem amsopt;
846 
847     PetscCall(PetscOptionItemCreate_Private(PetscOptionsObject, opt, ltext, man, OPTION_FLIST, &amsopt));
848     /* must use system malloc since SAWs may free this */
849     PetscCall(PetscStrdup(currentvalue ? currentvalue : "", (char **)&amsopt->data));
850     amsopt->flist = list;
851   }
852   PetscCall(PetscOptionsGetString(PetscOptionsObject->options, prefix, opt, value, len, &lset));
853   if (set) *set = lset;
854   if (ShouldPrintHelp(PetscOptionsObject)) PetscCall(PetscFunctionListPrintTypes(PetscOptionsObject->comm, stdout, Prefix(prefix), opt, ltext, man, list, currentvalue, lset ? value : currentvalue));
855   PetscFunctionReturn(PETSC_SUCCESS);
856 }
857 
858 #ifdef __cplusplus
859   #include <type_traits>
860 #endif
861 
862 PetscErrorCode PetscOptionsEList_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char ltext[], const char man[], const char *const *list, PetscInt ntext, const char currentvalue[], PetscInt *value, PetscBool *set)
863 {
864   const char *prefix = PetscOptionsObject->prefix;
865   PetscBool   lset;
866 
867   PetscFunctionBegin;
868   PetscAssertPointer(opt, 2);
869   PetscAssertPointer(value, 8);
870   if (set) PetscAssertPointer(set, 9);
871   if (!PetscOptionsObject->count) {
872     PetscOptionItem amsopt;
873 
874     PetscCall(PetscOptionItemCreate_Private(PetscOptionsObject, opt, ltext, man, OPTION_ELIST, &amsopt));
875     /* must use system malloc since SAWs may free this */
876     PetscCall(PetscStrdup(currentvalue ? currentvalue : "", (char **)&amsopt->data));
877     PetscCall(PetscStrNArrayallocpy(ntext, list, (char ***)&amsopt->list));
878     PetscCheck(ntext <= CHAR_MAX, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of list entries %" PetscInt_FMT " > %d", ntext, CHAR_MAX);
879 #ifdef __cplusplus
880     static_assert(std::is_same<typename std::decay<decltype(amsopt->nlist)>::type, char>::value, "");
881 #endif
882     amsopt->nlist = (char)ntext;
883   }
884   PetscCall(PetscOptionsGetEList(PetscOptionsObject->options, prefix, opt, list, ntext, value, &lset));
885   if (set) *set = lset;
886   if (ShouldPrintHelp(PetscOptionsObject)) {
887     const MPI_Comm comm = PetscOptionsObject->comm;
888 
889     PetscCall((*PetscHelpPrintf)(comm, "  -%s%s: <now %s : formerly %s> %s (choose one of)", Prefix(prefix), opt + 1, lset ? list[*value] : currentvalue, currentvalue, ltext));
890     for (PetscInt i = 0; i < ntext; ++i) PetscCall((*PetscHelpPrintf)(comm, " %s", list[i]));
891     PetscCall((*PetscHelpPrintf)(comm, " (%s)\n", ManSection(man)));
892   }
893   PetscFunctionReturn(PETSC_SUCCESS);
894 }
895 
896 PetscErrorCode PetscOptionsBoolGroupBegin_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], PetscBool *flg)
897 {
898   const char *prefix = PetscOptionsObject->prefix;
899 
900   PetscFunctionBegin;
901   PetscAssertPointer(opt, 2);
902   PetscAssertPointer(flg, 5);
903   if (!PetscOptionsObject->count) {
904     PetscOptionItem amsopt;
905 
906     PetscCall(PetscOptionItemCreate_Private(PetscOptionsObject, opt, text, man, OPTION_BOOL, &amsopt));
907     PetscCall(PetscMalloc(sizeof(PetscBool), &amsopt->data));
908 
909     *(PetscBool *)amsopt->data = PETSC_FALSE;
910   }
911   *flg = PETSC_FALSE;
912   PetscCall(PetscOptionsGetBool(PetscOptionsObject->options, prefix, opt, flg, NULL));
913   if (ShouldPrintHelp(PetscOptionsObject)) {
914     const MPI_Comm comm = PetscOptionsObject->comm;
915 
916     PetscCall((*PetscHelpPrintf)(comm, "  Pick at most one of -------------\n"));
917     PetscCall((*PetscHelpPrintf)(comm, "    -%s%s: %s (%s)\n", Prefix(prefix), opt + 1, text, ManSection(man)));
918   }
919   PetscFunctionReturn(PETSC_SUCCESS);
920 }
921 
922 PetscErrorCode PetscOptionsBoolGroup_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], PetscBool *flg)
923 {
924   const char *prefix = PetscOptionsObject->prefix;
925 
926   PetscFunctionBegin;
927   PetscAssertPointer(opt, 2);
928   PetscAssertPointer(flg, 5);
929   if (!PetscOptionsObject->count) {
930     PetscOptionItem amsopt;
931 
932     PetscCall(PetscOptionItemCreate_Private(PetscOptionsObject, opt, text, man, OPTION_BOOL, &amsopt));
933     PetscCall(PetscMalloc(sizeof(PetscBool), &amsopt->data));
934 
935     *(PetscBool *)amsopt->data = PETSC_FALSE;
936   }
937   *flg = PETSC_FALSE;
938   PetscCall(PetscOptionsGetBool(PetscOptionsObject->options, prefix, opt, flg, NULL));
939   if (ShouldPrintHelp(PetscOptionsObject)) PetscCall((*PetscHelpPrintf)(PetscOptionsObject->comm, "    -%s%s: %s (%s)\n", Prefix(prefix), opt + 1, text, ManSection(man)));
940   PetscFunctionReturn(PETSC_SUCCESS);
941 }
942 
943 PetscErrorCode PetscOptionsBoolGroupEnd_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], PetscBool *flg)
944 {
945   const char *prefix = PetscOptionsObject->prefix;
946 
947   PetscFunctionBegin;
948   PetscAssertPointer(opt, 2);
949   PetscAssertPointer(flg, 5);
950   if (!PetscOptionsObject->count) {
951     PetscOptionItem amsopt;
952 
953     PetscCall(PetscOptionItemCreate_Private(PetscOptionsObject, opt, text, man, OPTION_BOOL, &amsopt));
954     PetscCall(PetscMalloc(sizeof(PetscBool), &amsopt->data));
955 
956     *(PetscBool *)amsopt->data = PETSC_FALSE;
957   }
958   *flg = PETSC_FALSE;
959   PetscCall(PetscOptionsGetBool(PetscOptionsObject->options, prefix, opt, flg, NULL));
960   if (ShouldPrintHelp(PetscOptionsObject)) PetscCall((*PetscHelpPrintf)(PetscOptionsObject->comm, "    -%s%s: %s (%s)\n", Prefix(prefix), opt + 1, text, ManSection(man)));
961   PetscFunctionReturn(PETSC_SUCCESS);
962 }
963 
964 PetscErrorCode PetscOptionsBool_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], PetscBool currentvalue, PetscBool *flg, PetscBool *set)
965 {
966   const char *prefix = PetscOptionsObject->prefix;
967   PetscBool   iset;
968 
969   PetscFunctionBegin;
970   PetscAssertPointer(opt, 2);
971   PetscAssertPointer(flg, 6);
972   if (set) PetscAssertPointer(set, 7);
973   if (!PetscOptionsObject->count) {
974     PetscOptionItem amsopt;
975 
976     PetscCall(PetscOptionItemCreate_Private(PetscOptionsObject, opt, text, man, OPTION_BOOL, &amsopt));
977     PetscCall(PetscMalloc(sizeof(PetscBool), &amsopt->data));
978 
979     *(PetscBool *)amsopt->data = currentvalue;
980   }
981   PetscCall(PetscOptionsGetBool(PetscOptionsObject->options, prefix, opt, flg, &iset));
982   if (set) *set = iset;
983   if (ShouldPrintHelp(PetscOptionsObject)) {
984     const char *curvalue = PetscBools[currentvalue];
985 
986     PetscCall((*PetscHelpPrintf)(PetscOptionsObject->comm, "  -%s%s: <now %s : formerly %s> %s (%s)\n", Prefix(prefix), opt + 1, iset ? PetscBools[*flg] : curvalue, curvalue, text, ManSection(man)));
987   }
988   PetscFunctionReturn(PETSC_SUCCESS);
989 }
990 
991 PetscErrorCode PetscOptionsRealArray_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], PetscReal value[], PetscInt *n, PetscBool *set)
992 {
993   const char *prefix = PetscOptionsObject->prefix;
994 
995   PetscFunctionBegin;
996   PetscAssertPointer(opt, 2);
997   PetscAssertPointer(n, 6);
998   PetscCheck(*n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "n (%" PetscInt_FMT ") cannot be negative", *n);
999   if (*n) PetscAssertPointer(value, 5);
1000   if (set) PetscAssertPointer(set, 7);
1001   if (!PetscOptionsObject->count) {
1002     const PetscInt  nv = *n;
1003     PetscReal      *vals;
1004     PetscOptionItem amsopt;
1005 
1006     PetscCall(PetscOptionItemCreate_Private(PetscOptionsObject, opt, text, man, OPTION_REAL_ARRAY, &amsopt));
1007     PetscCall(PetscMalloc(nv * sizeof(*vals), &vals));
1008     for (PetscInt i = 0; i < nv; ++i) vals[i] = value[i];
1009     amsopt->arraylength = nv;
1010     amsopt->data        = vals;
1011   }
1012   PetscCall(PetscOptionsGetRealArray(PetscOptionsObject->options, prefix, opt, value, n, set));
1013   if (ShouldPrintHelp(PetscOptionsObject)) {
1014     const PetscInt nv   = *n;
1015     const MPI_Comm comm = PetscOptionsObject->comm;
1016 
1017     PetscCall((*PetscHelpPrintf)(comm, "  -%s%s: <%g", Prefix(prefix), opt + 1, (double)value[0]));
1018     for (PetscInt i = 1; i < nv; ++i) PetscCall((*PetscHelpPrintf)(comm, ",%g", (double)value[i]));
1019     PetscCall((*PetscHelpPrintf)(comm, ">: %s (%s)\n", text, ManSection(man)));
1020   }
1021   PetscFunctionReturn(PETSC_SUCCESS);
1022 }
1023 
1024 PetscErrorCode PetscOptionsScalarArray_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], PetscScalar value[], PetscInt *n, PetscBool *set)
1025 {
1026   const char *prefix = PetscOptionsObject->prefix;
1027 
1028   PetscFunctionBegin;
1029   PetscAssertPointer(opt, 2);
1030   PetscAssertPointer(n, 6);
1031   PetscCheck(*n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "n (%" PetscInt_FMT ") cannot be negative", *n);
1032   if (*n) PetscAssertPointer(value, 5);
1033   if (set) PetscAssertPointer(set, 7);
1034   if (!PetscOptionsObject->count) {
1035     const PetscInt  nv = *n;
1036     PetscOptionItem amsopt;
1037     PetscScalar    *vals;
1038 
1039     PetscCall(PetscOptionItemCreate_Private(PetscOptionsObject, opt, text, man, OPTION_SCALAR_ARRAY, &amsopt));
1040     PetscCall(PetscMalloc(nv * sizeof(*vals), &vals));
1041     for (PetscInt i = 0; i < nv; ++i) vals[i] = value[i];
1042     amsopt->arraylength = nv;
1043     amsopt->data        = vals;
1044   }
1045   PetscCall(PetscOptionsGetScalarArray(PetscOptionsObject->options, prefix, opt, value, n, set));
1046   if (ShouldPrintHelp(PetscOptionsObject)) {
1047     const PetscInt nv   = *n;
1048     const MPI_Comm comm = PetscOptionsObject->comm;
1049 
1050     PetscCall((*PetscHelpPrintf)(comm, "  -%s%s: <%g+%gi", Prefix(prefix), opt + 1, (double)PetscRealPart(value[0]), (double)PetscImaginaryPart(value[0])));
1051     for (PetscInt i = 1; i < nv; ++i) PetscCall((*PetscHelpPrintf)(comm, ",%g+%gi", (double)PetscRealPart(value[i]), (double)PetscImaginaryPart(value[i])));
1052     PetscCall((*PetscHelpPrintf)(comm, ">: %s (%s)\n", text, ManSection(man)));
1053   }
1054   PetscFunctionReturn(PETSC_SUCCESS);
1055 }
1056 
1057 PetscErrorCode PetscOptionsIntArray_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], PetscInt value[], PetscInt *n, PetscBool *set)
1058 {
1059   const char *prefix = PetscOptionsObject->prefix;
1060 
1061   PetscFunctionBegin;
1062   PetscAssertPointer(opt, 2);
1063   PetscAssertPointer(n, 6);
1064   PetscCheck(*n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "n (%" PetscInt_FMT ") cannot be negative", *n);
1065   if (*n) PetscAssertPointer(value, 5);
1066   if (set) PetscAssertPointer(set, 7);
1067   if (!PetscOptionsObject->count) {
1068     const PetscInt  nv = *n;
1069     PetscInt       *vals;
1070     PetscOptionItem amsopt;
1071 
1072     PetscCall(PetscOptionItemCreate_Private(PetscOptionsObject, opt, text, man, OPTION_INT_ARRAY, &amsopt));
1073     PetscCall(PetscMalloc1(nv, &vals));
1074     for (PetscInt i = 0; i < nv; ++i) vals[i] = value[i];
1075     amsopt->arraylength = nv;
1076     amsopt->data        = vals;
1077   }
1078   PetscCall(PetscOptionsGetIntArray(PetscOptionsObject->options, prefix, opt, value, n, set));
1079   if (ShouldPrintHelp(PetscOptionsObject)) {
1080     const PetscInt nv   = *n;
1081     const MPI_Comm comm = PetscOptionsObject->comm;
1082 
1083     PetscCall((*PetscHelpPrintf)(comm, "  -%s%s: <%" PetscInt_FMT, Prefix(prefix), opt + 1, value[0]));
1084     for (PetscInt i = 1; i < nv; ++i) PetscCall((*PetscHelpPrintf)(comm, ",%" PetscInt_FMT, value[i]));
1085     PetscCall((*PetscHelpPrintf)(comm, ">: %s (%s)\n", text, ManSection(man)));
1086   }
1087   PetscFunctionReturn(PETSC_SUCCESS);
1088 }
1089 
1090 PetscErrorCode PetscOptionsStringArray_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], char *value[], PetscInt *nmax, PetscBool *set)
1091 {
1092   const char *prefix = PetscOptionsObject->prefix;
1093 
1094   PetscFunctionBegin;
1095   PetscAssertPointer(opt, 2);
1096   PetscAssertPointer(nmax, 6);
1097   PetscCheck(*nmax >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "n (%" PetscInt_FMT ") cannot be negative", *nmax);
1098   if (*nmax) PetscAssertPointer(value, 5);
1099   if (set) PetscAssertPointer(set, 7);
1100   if (!PetscOptionsObject->count) {
1101     const PetscInt  nmaxv = *nmax;
1102     PetscOptionItem amsopt;
1103 
1104     PetscCall(PetscOptionItemCreate_Private(PetscOptionsObject, opt, text, man, OPTION_STRING_ARRAY, &amsopt));
1105     PetscCall(PetscMalloc1(nmaxv, (char **)&amsopt->data));
1106     amsopt->arraylength = nmaxv;
1107   }
1108   PetscCall(PetscOptionsGetStringArray(PetscOptionsObject->options, prefix, opt, value, nmax, set));
1109   if (ShouldPrintHelp(PetscOptionsObject)) PetscCall((*PetscHelpPrintf)(PetscOptionsObject->comm, "  -%s%s: <string1,string2,...>: %s (%s)\n", Prefix(prefix), opt + 1, text, ManSection(man)));
1110   PetscFunctionReturn(PETSC_SUCCESS);
1111 }
1112 
1113 PetscErrorCode PetscOptionsBoolArray_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], PetscBool value[], PetscInt *n, PetscBool *set)
1114 {
1115   const char *prefix = PetscOptionsObject->prefix;
1116 
1117   PetscFunctionBegin;
1118   PetscAssertPointer(opt, 2);
1119   PetscAssertPointer(n, 6);
1120   PetscCheck(*n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "n (%" PetscInt_FMT ") cannot be negative", *n);
1121   if (*n) PetscAssertPointer(value, 5);
1122   if (set) PetscAssertPointer(set, 7);
1123   if (!PetscOptionsObject->count) {
1124     const PetscInt  nv = *n;
1125     PetscBool      *vals;
1126     PetscOptionItem amsopt;
1127 
1128     PetscCall(PetscOptionItemCreate_Private(PetscOptionsObject, opt, text, man, OPTION_BOOL_ARRAY, &amsopt));
1129     PetscCall(PetscMalloc1(nv, &vals));
1130     for (PetscInt i = 0; i < nv; ++i) vals[i] = value[i];
1131     amsopt->arraylength = nv;
1132     amsopt->data        = vals;
1133   }
1134   PetscCall(PetscOptionsGetBoolArray(PetscOptionsObject->options, prefix, opt, value, n, set));
1135   if (ShouldPrintHelp(PetscOptionsObject)) {
1136     const PetscInt nv   = *n;
1137     const MPI_Comm comm = PetscOptionsObject->comm;
1138 
1139     PetscCall((*PetscHelpPrintf)(comm, "  -%s%s: <%d", Prefix(prefix), opt + 1, value[0]));
1140     for (PetscInt i = 1; i < nv; ++i) PetscCall((*PetscHelpPrintf)(comm, ",%d", value[i]));
1141     PetscCall((*PetscHelpPrintf)(comm, ">: %s (%s)\n", text, ManSection(man)));
1142   }
1143   PetscFunctionReturn(PETSC_SUCCESS);
1144 }
1145 
1146 /*MC
1147   PetscOptionsViewer - Creates a viewer appropriate for the type indicated by the user
1148 
1149   Synopsis:
1150   #include <petscviewer.h>
1151   PetscErrorCode PetscOptionsViewer(const char opt[], const char text[], const char man[], PetscViewer *viewer, PetscViewerFormat *format, PetscBool *set)
1152 
1153   Logically Collective on the communicator passed in `PetscOptionsBegin()`
1154 
1155   Input Parameters:
1156 + opt  - option name
1157 . text - short string that describes the option
1158 - man  - manual page with additional information on option
1159 
1160   Output Parameters:
1161 + viewer - the viewer
1162 . format - the PetscViewerFormat requested by the user, pass `NULL` if not needed
1163 - set    - `PETSC_TRUE` if found, else `PETSC_FALSE`
1164 
1165   Level: beginner
1166 
1167   Notes:
1168   Must be between a `PetscOptionsBegin()` and a `PetscOptionsEnd()`
1169 
1170   See `PetscOptionsCreateViewer()` for the format of the supplied viewer and its options
1171 
1172 .seealso: `PetscOptionsCreateViewer()`, `PetscOptionsHasName()`, `PetscOptionsGetString()`, `PetscOptionsGetInt()`,
1173           `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()`
1174           `PetscOptionsInt()`, `PetscOptionsString()`, `PetscOptionsReal()`,
1175           `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
1176           `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
1177           `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
1178           `PetscOptionsFList()`, `PetscOptionsEList()`
1179 M*/
1180 PetscErrorCode PetscOptionsViewer_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], PetscViewer *viewer, PetscViewerFormat *format, PetscBool *set)
1181 {
1182   const MPI_Comm comm   = PetscOptionsObject->comm;
1183   const char    *prefix = PetscOptionsObject->prefix;
1184 
1185   PetscFunctionBegin;
1186   PetscAssertPointer(opt, 2);
1187   PetscAssertPointer(viewer, 5);
1188   if (format) PetscAssertPointer(format, 6);
1189   if (set) PetscAssertPointer(set, 7);
1190   if (!PetscOptionsObject->count) {
1191     PetscOptionItem amsopt;
1192 
1193     PetscCall(PetscOptionItemCreate_Private(PetscOptionsObject, opt, text, man, OPTION_STRING, &amsopt));
1194     /* must use system malloc since SAWs may free this */
1195     PetscCall(PetscStrdup("", (char **)&amsopt->data));
1196   }
1197   PetscCall(PetscOptionsCreateViewer(comm, PetscOptionsObject->options, prefix, opt, viewer, format, set));
1198   if (ShouldPrintHelp(PetscOptionsObject)) PetscCall((*PetscHelpPrintf)(comm, "  -%s%s: <%s>: %s (%s)\n", Prefix(prefix), opt + 1, "", text, ManSection(man)));
1199   PetscFunctionReturn(PETSC_SUCCESS);
1200 }
1201