xref: /petsc/src/sys/objects/aoptions.c (revision 6497c311e7b976d467be1503c1effce92a60525c)
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     len;
357         char      *value;
358         PetscBool  foundrange;
359         PetscInt   i;
360 
361         next->set = PETSC_TRUE;
362         value     = str;
363         PetscCall(PetscTokenCreate(value, ',', &token));
364         PetscCall(PetscTokenFind(token, &value));
365         while (n < nmax) {
366           if (!value) break;
367 
368           /* look for form  d-D where d and D are integers */
369           foundrange = PETSC_FALSE;
370           PetscCall(PetscStrlen(value, &len));
371           if (value[0] == '-') i = 2;
372           else i = 1;
373           for (; i < (PetscInt)len; i++) {
374             if (value[i] == '-') {
375               PetscCheck(i != (PetscInt)(len - 1), PETSC_COMM_SELF, PETSC_ERR_USER, "Error in %" PetscInt_FMT "-th array entry %s", n, value);
376               value[i] = 0;
377               PetscCall(PetscOptionsStringToInt(value, &start));
378               PetscCall(PetscOptionsStringToInt(value + i + 1, &end));
379               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);
380               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);
381               for (; start < end; start++) {
382                 *dvalue = start;
383                 dvalue++;
384                 n++;
385               }
386               foundrange = PETSC_TRUE;
387               break;
388             }
389           }
390           if (!foundrange) {
391             PetscCall(PetscOptionsStringToInt(value, dvalue));
392             dvalue++;
393             n++;
394           }
395           PetscCall(PetscTokenFind(token, &value));
396         }
397         PetscCall(PetscTokenDestroy(&token));
398       }
399       break;
400     case OPTION_REAL_ARRAY:
401       PetscCall(PetscPrintf(PETSC_COMM_WORLD, "-%s%s: <", PetscOptionsObject->prefix ? PetscOptionsObject->prefix : "", next->option + 1));
402       valr = (PetscReal *)next->data;
403       for (PetscInt i = 0; i < next->arraylength; i++) {
404         PetscCall(PetscPrintf(PETSC_COMM_WORLD, "%g", (double)valr[i]));
405         if (i < next->arraylength - 1) PetscCall(PetscPrintf(PETSC_COMM_WORLD, ","));
406       }
407       PetscCall(PetscPrintf(PETSC_COMM_WORLD, ">: %s (%s) ", next->text, next->man));
408       PetscCall(PetscScanString(PETSC_COMM_WORLD, 512, str));
409       if (str[0]) {
410         PetscToken token;
411         PetscInt   n = 0, nmax = next->arraylength;
412         PetscReal *dvalue = (PetscReal *)next->data;
413         char      *value;
414 
415         next->set = PETSC_TRUE;
416         value     = str;
417         PetscCall(PetscTokenCreate(value, ',', &token));
418         PetscCall(PetscTokenFind(token, &value));
419         while (n < nmax) {
420           if (!value) break;
421           PetscCall(PetscOptionsStringToReal(value, dvalue));
422           dvalue++;
423           n++;
424           PetscCall(PetscTokenFind(token, &value));
425         }
426         PetscCall(PetscTokenDestroy(&token));
427       }
428       break;
429     case OPTION_INT:
430       PetscCall(PetscPrintf(PETSC_COMM_WORLD, "-%s%s: <%d>: %s (%s) ", PetscOptionsObject->prefix ? PetscOptionsObject->prefix : "", next->option + 1, *(int *)next->data, next->text, next->man));
431       PetscCall(PetscScanString(PETSC_COMM_WORLD, 512, str));
432       if (str[0]) {
433   #if defined(PETSC_SIZEOF_LONG_LONG)
434         long long lid;
435         sscanf(str, "%lld", &lid);
436         PetscCheck(lid <= PETSC_MAX_INT && lid >= PETSC_MIN_INT, PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE, "Argument: -%s%s %lld", PetscOptionsObject->prefix ? PetscOptionsObject->prefix : "", next->option + 1, lid);
437   #else
438         long lid;
439         sscanf(str, "%ld", &lid);
440         PetscCheck(lid <= PETSC_MAX_INT && lid >= PETSC_MIN_INT, PETSC_COMM_WORLD, PETSC_ERR_ARG_OUTOFRANGE, "Argument: -%s%s %ld", PetscOptionsObject->prefix ? PetscOptionsObject->prefix : "", next->option + 1, lid);
441   #endif
442 
443         next->set                 = PETSC_TRUE;
444         *((PetscInt *)next->data) = (PetscInt)lid;
445       }
446       break;
447     case OPTION_REAL:
448       PetscCall(PetscPrintf(PETSC_COMM_WORLD, "-%s%s: <%g>: %s (%s) ", PetscOptionsObject->prefix ? PetscOptionsObject->prefix : "", next->option + 1, *(double *)next->data, next->text, next->man));
449       PetscCall(PetscScanString(PETSC_COMM_WORLD, 512, str));
450       if (str[0]) {
451   #if defined(PETSC_USE_REAL_SINGLE)
452         sscanf(str, "%e", &ir);
453   #elif defined(PETSC_USE_REAL___FP16)
454         float irtemp;
455         sscanf(str, "%e", &irtemp);
456         ir = irtemp;
457   #elif defined(PETSC_USE_REAL_DOUBLE)
458         sscanf(str, "%le", &ir);
459   #elif defined(PETSC_USE_REAL___FLOAT128)
460         ir = strtoflt128(str, 0);
461   #else
462         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Unknown scalar type");
463   #endif
464         next->set                  = PETSC_TRUE;
465         *((PetscReal *)next->data) = ir;
466       }
467       break;
468     case OPTION_BOOL:
469       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));
470       PetscCall(PetscScanString(PETSC_COMM_WORLD, 512, str));
471       if (str[0]) {
472         PetscCall(PetscOptionsStringToBool(str, &bid));
473         next->set                  = PETSC_TRUE;
474         *((PetscBool *)next->data) = bid;
475       }
476       break;
477     case OPTION_STRING:
478       PetscCall(PetscPrintf(PETSC_COMM_WORLD, "-%s%s: <%s>: %s (%s) ", PetscOptionsObject->prefix ? PetscOptionsObject->prefix : "", next->option + 1, (char *)next->data, next->text, next->man));
479       PetscCall(PetscScanString(PETSC_COMM_WORLD, 512, str));
480       if (str[0]) {
481         next->set = PETSC_TRUE;
482         /* must use system malloc since SAWs may free this */
483         PetscCall(PetscStrdup(str, (char **)&next->data));
484       }
485       break;
486     case OPTION_FLIST:
487       PetscCall(PetscFunctionListPrintTypes(PETSC_COMM_WORLD, stdout, PetscOptionsObject->prefix, next->option, next->text, next->man, next->flist, (char *)next->data, (char *)next->data));
488       PetscCall(PetscScanString(PETSC_COMM_WORLD, 512, str));
489       if (str[0]) {
490         PetscOptionsObject->changedmethod = PETSC_TRUE;
491         next->set                         = PETSC_TRUE;
492         /* must use system malloc since SAWs may free this */
493         PetscCall(PetscStrdup(str, (char **)&next->data));
494       }
495       break;
496     default:
497       break;
498     }
499     next = next->next;
500   }
501   PetscFunctionReturn(PETSC_SUCCESS);
502 }
503 #endif
504 
505 PetscErrorCode PetscOptionsEnd_Private(PetscOptionItems *PetscOptionsObject)
506 {
507   PetscOptionItem next, last;
508 
509   PetscFunctionBegin;
510   if (PetscOptionsObject->next) {
511     if (!PetscOptionsObject->count) {
512 #if defined(PETSC_HAVE_SAWS)
513       PetscCall(PetscOptionsSAWsInput(PetscOptionsObject));
514 #else
515       PetscCall(PetscOptionsGetFromTextInput(PetscOptionsObject));
516 #endif
517     }
518   }
519 
520   PetscCall(PetscFree(PetscOptionsObject->title));
521 
522   /* reset counter to -2; this updates the screen with the new options for the selected method */
523   if (PetscOptionsObject->changedmethod) PetscOptionsObject->count = -2;
524   /* reset alreadyprinted flag */
525   PetscOptionsObject->alreadyprinted = PETSC_FALSE;
526   if (PetscOptionsObject->object) PetscOptionsObject->object->optionsprinted = PETSC_TRUE;
527   PetscOptionsObject->object = NULL;
528 
529   while ((next = PetscOptionsObject->next)) {
530     const PetscOptionType type        = next->type;
531     const size_t          arraylength = next->arraylength;
532     void                 *data        = next->data;
533 
534     if (next->set) {
535       char option[256], value[1024], tmp[32];
536 
537       if (PetscOptionsObject->prefix) {
538         PetscCall(PetscStrncpy(option, "-", sizeof(option)));
539         PetscCall(PetscStrlcat(option, PetscOptionsObject->prefix, sizeof(option)));
540         PetscCall(PetscStrlcat(option, next->option + 1, sizeof(option)));
541       } else {
542         PetscCall(PetscStrncpy(option, next->option, sizeof(option)));
543       }
544 
545       switch (type) {
546       case OPTION_HEAD:
547         break;
548       case OPTION_INT_ARRAY:
549         PetscCall(PetscSNPrintf(value, PETSC_STATIC_ARRAY_LENGTH(value), "%d", (int)((PetscInt *)data)[0]));
550         for (size_t j = 1; j < arraylength; ++j) {
551           PetscCall(PetscSNPrintf(tmp, PETSC_STATIC_ARRAY_LENGTH(tmp), "%d", (int)((PetscInt *)data)[j]));
552           PetscCall(PetscStrlcat(value, ",", sizeof(value)));
553           PetscCall(PetscStrlcat(value, tmp, sizeof(value)));
554         }
555         break;
556       case OPTION_INT:
557         PetscCall(PetscSNPrintf(value, PETSC_STATIC_ARRAY_LENGTH(value), "%d", (int)*(PetscInt *)data));
558         break;
559       case OPTION_REAL:
560         PetscCall(PetscSNPrintf(value, PETSC_STATIC_ARRAY_LENGTH(value), "%g", (double)*(PetscReal *)data));
561         break;
562       case OPTION_REAL_ARRAY:
563         PetscCall(PetscSNPrintf(value, PETSC_STATIC_ARRAY_LENGTH(value), "%g", (double)((PetscReal *)data)[0]));
564         for (size_t j = 1; j < arraylength; ++j) {
565           PetscCall(PetscSNPrintf(tmp, PETSC_STATIC_ARRAY_LENGTH(tmp), "%g", (double)((PetscReal *)data)[j]));
566           PetscCall(PetscStrlcat(value, ",", sizeof(value)));
567           PetscCall(PetscStrlcat(value, tmp, sizeof(value)));
568         }
569         break;
570       case OPTION_SCALAR_ARRAY:
571         PetscCall(PetscSNPrintf(value, PETSC_STATIC_ARRAY_LENGTH(value), "%g+%gi", (double)PetscRealPart(((PetscScalar *)data)[0]), (double)PetscImaginaryPart(((PetscScalar *)data)[0])));
572         for (size_t j = 1; j < arraylength; ++j) {
573           PetscCall(PetscSNPrintf(tmp, PETSC_STATIC_ARRAY_LENGTH(tmp), "%g+%gi", (double)PetscRealPart(((PetscScalar *)data)[j]), (double)PetscImaginaryPart(((PetscScalar *)data)[j])));
574           PetscCall(PetscStrlcat(value, ",", sizeof(value)));
575           PetscCall(PetscStrlcat(value, tmp, sizeof(value)));
576         }
577         break;
578       case OPTION_BOOL:
579         PetscCall(PetscSNPrintf(value, PETSC_STATIC_ARRAY_LENGTH(value), "%d", *(int *)data));
580         break;
581       case OPTION_BOOL_ARRAY:
582         PetscCall(PetscSNPrintf(value, PETSC_STATIC_ARRAY_LENGTH(value), "%d", (int)((PetscBool *)data)[0]));
583         for (size_t j = 1; j < arraylength; ++j) {
584           PetscCall(PetscSNPrintf(tmp, PETSC_STATIC_ARRAY_LENGTH(tmp), "%d", (int)((PetscBool *)data)[j]));
585           PetscCall(PetscStrlcat(value, ",", sizeof(value)));
586           PetscCall(PetscStrlcat(value, tmp, sizeof(value)));
587         }
588         break;
589       case OPTION_FLIST: // fall-through
590       case OPTION_ELIST: // fall-through
591       case OPTION_STRING:
592         PetscCall(PetscStrncpy(value, (char *)data, sizeof(value)));
593         break;
594       case OPTION_STRING_ARRAY:
595         PetscCall(PetscSNPrintf(value, PETSC_STATIC_ARRAY_LENGTH(value), "%s", ((char **)data)[0]));
596         for (size_t j = 1; j < arraylength; j++) {
597           PetscCall(PetscSNPrintf(tmp, PETSC_STATIC_ARRAY_LENGTH(tmp), "%s", ((char **)data)[j]));
598           PetscCall(PetscStrlcat(value, ",", sizeof(value)));
599           PetscCall(PetscStrlcat(value, tmp, sizeof(value)));
600         }
601         break;
602       }
603       PetscCall(PetscOptionsSetValue(PetscOptionsObject->options, option, value));
604     }
605     if (type == OPTION_ELIST) PetscCall(PetscStrNArrayDestroy(next->nlist, (char ***)&next->list));
606     PetscCall(PetscFree(next->text));
607     PetscCall(PetscFree(next->option));
608     PetscCall(PetscFree(next->man));
609     PetscCall(PetscFree(next->edata));
610 
611     if (type == OPTION_STRING || type == OPTION_FLIST || type == OPTION_ELIST) {
612       free(data);
613     } else {
614       // use next->data instead of data because PetscFree() sets it to NULL
615       PetscCall(PetscFree(next->data));
616     }
617 
618     last                     = next;
619     PetscOptionsObject->next = next->next;
620     PetscCall(PetscFree(last));
621   }
622   PetscCall(PetscFree(PetscOptionsObject->prefix));
623   PetscOptionsObject->next = NULL;
624   PetscFunctionReturn(PETSC_SUCCESS);
625 }
626 
627 static PetscErrorCode GetListLength(const char *const *list, PetscInt *len)
628 {
629   PetscInt retlen = 0;
630 
631   PetscFunctionBegin;
632   PetscAssertPointer(len, 2);
633   while (list[retlen]) {
634     PetscAssertPointer(list[retlen], 1);
635     PetscCheck(++retlen < 50, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "List argument appears to be wrong or have more than 50 entries");
636   }
637   PetscCheck(retlen > 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "List argument must have at least 2 entries: typename and type prefix");
638   /* drop item name and prefix*/
639   *len = retlen - 2;
640   PetscFunctionReturn(PETSC_SUCCESS);
641 }
642 
643 PetscErrorCode PetscOptionsEnum_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], const char *const *list, PetscEnum currentvalue, PetscEnum *value, PetscBool *set)
644 {
645   PetscInt  ntext = 0;
646   PetscInt  tval;
647   PetscBool tflg;
648 
649   PetscFunctionBegin;
650   PetscAssertPointer(opt, 2);
651   PetscAssertPointer(list, 5);
652   PetscAssertPointer(value, 7);
653   if (set) PetscAssertPointer(set, 8);
654   PetscCall(GetListLength(list, &ntext));
655   PetscCall(PetscOptionsEList_Private(PetscOptionsObject, opt, text, man, list, ntext, list[currentvalue], &tval, &tflg));
656   /* with PETSC_USE_64BIT_INDICES sizeof(PetscInt) != sizeof(PetscEnum) */
657   if (tflg) *value = (PetscEnum)tval;
658   if (set) *set = tflg;
659   PetscFunctionReturn(PETSC_SUCCESS);
660 }
661 
662 PetscErrorCode PetscOptionsEnumArray_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], const char *const *list, PetscEnum value[], PetscInt *n, PetscBool *set)
663 {
664   PetscInt    nlist  = 0;
665   const char *prefix = PetscOptionsObject->prefix;
666 
667   PetscFunctionBegin;
668   PetscAssertPointer(opt, 2);
669   PetscAssertPointer(list, 5);
670   PetscAssertPointer(value, 6);
671   PetscAssertPointer(n, 7);
672   PetscCheck(*n > 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "n (%" PetscInt_FMT ") must be > 0", *n);
673   if (set) PetscAssertPointer(set, 8);
674   PetscCall(GetListLength(list, &nlist));
675   PetscCall(PetscOptionsGetEnumArray(PetscOptionsObject->options, prefix, opt, list, value, n, set));
676   if (ShouldPrintHelp(PetscOptionsObject)) {
677     const MPI_Comm comm = PetscOptionsObject->comm;
678     const PetscInt nv   = *n;
679 
680     PetscCall((*PetscHelpPrintf)(comm, "  -%s%s: <%s", Prefix(prefix), opt + 1, list[value[0]]));
681     for (PetscInt i = 1; i < nv; ++i) PetscCall((*PetscHelpPrintf)(comm, ",%s", list[value[i]]));
682     PetscCall((*PetscHelpPrintf)(comm, ">: %s (choose from)", text));
683     for (PetscInt i = 0; i < nlist; ++i) PetscCall((*PetscHelpPrintf)(comm, " %s", list[i]));
684     PetscCall((*PetscHelpPrintf)(comm, " (%s)\n", ManSection(man)));
685   }
686   PetscFunctionReturn(PETSC_SUCCESS);
687 }
688 
689 PetscErrorCode PetscOptionsInt_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], PetscInt currentvalue, PetscInt *value, PetscBool *set, PetscInt lb, PetscInt ub)
690 {
691   const char        *prefix  = PetscOptionsObject->prefix;
692   const PetscOptions options = PetscOptionsObject->options;
693   PetscBool          wasset;
694 
695   PetscFunctionBegin;
696   PetscAssertPointer(opt, 2);
697   PetscAssertPointer(value, 6);
698   if (set) PetscAssertPointer(set, 7);
699   PetscCheck(currentvalue >= lb, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Current value %" PetscInt_FMT " less than allowed bound %" PetscInt_FMT, currentvalue, lb);
700   PetscCheck(currentvalue <= ub, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Current value %" PetscInt_FMT " greater than allowed bound %" PetscInt_FMT, currentvalue, ub);
701   if (!PetscOptionsObject->count) {
702     PetscOptionItem amsopt;
703 
704     PetscCall(PetscOptionItemCreate_Private(PetscOptionsObject, opt, text, man, OPTION_INT, &amsopt));
705     PetscCall(PetscMalloc(sizeof(PetscInt), &amsopt->data));
706     *(PetscInt *)amsopt->data = currentvalue;
707 
708     PetscCall(PetscOptionsGetInt(options, prefix, opt, &currentvalue, &wasset));
709     if (wasset) *(PetscInt *)amsopt->data = currentvalue;
710   }
711   PetscCall(PetscOptionsGetInt(options, prefix, opt, value, &wasset));
712   PetscCheck(!wasset || *value >= lb, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Newly set value %" PetscInt_FMT " less than allowed bound %" PetscInt_FMT, *value, lb);
713   PetscCheck(!wasset || *value <= ub, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Newly set value %" PetscInt_FMT " greater than allowed bound %" PetscInt_FMT, *value, ub);
714   if (set) *set = wasset;
715   if (ShouldPrintHelp(PetscOptionsObject)) {
716     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)));
717   }
718   PetscFunctionReturn(PETSC_SUCCESS);
719 }
720 
721 PetscErrorCode PetscOptionsMPIInt_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], PetscMPIInt currentvalue, PetscMPIInt *value, PetscBool *set, PetscMPIInt lb, PetscMPIInt ub)
722 {
723   const char        *prefix  = PetscOptionsObject->prefix;
724   const PetscOptions options = PetscOptionsObject->options;
725   PetscBool          wasset;
726 
727   PetscFunctionBegin;
728   PetscAssertPointer(opt, 2);
729   PetscAssertPointer(value, 6);
730   if (set) PetscAssertPointer(set, 7);
731   PetscCheck(currentvalue >= lb, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Current value %d less than allowed bound %d", currentvalue, lb);
732   PetscCheck(currentvalue <= ub, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Current value %d greater than allowed bound %d", currentvalue, ub);
733   if (!PetscOptionsObject->count) {
734     PetscOptionItem amsopt;
735 
736     PetscCall(PetscOptionItemCreate_Private(PetscOptionsObject, opt, text, man, OPTION_INT, &amsopt));
737     PetscCall(PetscMalloc(sizeof(PetscInt), &amsopt->data));
738     *(PetscMPIInt *)amsopt->data = currentvalue;
739 
740     PetscCall(PetscOptionsGetMPIInt(options, prefix, opt, &currentvalue, &wasset));
741     if (wasset) *(PetscMPIInt *)amsopt->data = currentvalue;
742   }
743   PetscCall(PetscOptionsGetMPIInt(options, prefix, opt, value, &wasset));
744   PetscCheck(!wasset || *value >= lb, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Newly set value %d less than allowed bound %d", *value, lb);
745   PetscCheck(!wasset || *value <= ub, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Newly set value %d greater than allowed bound %d", *value, ub);
746   if (set) *set = wasset;
747   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))); }
748   PetscFunctionReturn(PETSC_SUCCESS);
749 }
750 
751 PetscErrorCode PetscOptionsString_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], const char currentvalue[], char value[], size_t len, PetscBool *set)
752 {
753   const char *prefix = PetscOptionsObject->prefix;
754   PetscBool   lset;
755 
756   PetscFunctionBegin;
757   PetscAssertPointer(opt, 2);
758   PetscAssertPointer(value, 6);
759   if (set) PetscAssertPointer(set, 8);
760   if (!PetscOptionsObject->count) {
761     PetscOptionItem amsopt;
762 
763     PetscCall(PetscOptionItemCreate_Private(PetscOptionsObject, opt, text, man, OPTION_STRING, &amsopt));
764     /* must use system malloc since SAWs may free this */
765     PetscCall(PetscStrdup(currentvalue ? currentvalue : "", (char **)&amsopt->data));
766   }
767   PetscCall(PetscOptionsGetString(PetscOptionsObject->options, prefix, opt, value, len, &lset));
768   if (set) *set = lset;
769   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)));
770   PetscFunctionReturn(PETSC_SUCCESS);
771 }
772 
773 PetscErrorCode PetscOptionsReal_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], PetscReal currentvalue, PetscReal *value, PetscBool *set, PetscReal lb, PetscReal ub)
774 {
775   const char        *prefix  = PetscOptionsObject->prefix;
776   const PetscOptions options = PetscOptionsObject->options;
777   PetscBool          wasset;
778 
779   PetscFunctionBegin;
780   PetscAssertPointer(opt, 2);
781   PetscAssertPointer(value, 6);
782   if (set) PetscAssertPointer(set, 7);
783   PetscCheck(currentvalue >= lb, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Current value %g less than allowed bound %g", (double)currentvalue, (double)lb);
784   PetscCheck(currentvalue <= ub, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Current value %g greater than allowed bound %g", (double)currentvalue, (double)ub);
785   if (!PetscOptionsObject->count) {
786     PetscOptionItem amsopt;
787 
788     PetscCall(PetscOptionItemCreate_Private(PetscOptionsObject, opt, text, man, OPTION_REAL, &amsopt));
789     PetscCall(PetscMalloc(sizeof(PetscReal), &amsopt->data));
790     *(PetscReal *)amsopt->data = currentvalue;
791 
792     PetscCall(PetscOptionsGetReal(options, prefix, opt, &currentvalue, &wasset));
793     if (wasset) *(PetscReal *)amsopt->data = currentvalue;
794   }
795   PetscCall(PetscOptionsGetReal(PetscOptionsObject->options, prefix, opt, value, &wasset));
796   PetscCheck(!wasset || *value >= lb, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Newly set value %g less than allowed bound %g", (double)*value, (double)lb);
797   PetscCheck(!wasset || *value <= ub, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Newly set value %g greater than allowed bound %g", (double)*value, (double)ub);
798   if (set) *set = wasset;
799   if (ShouldPrintHelp(PetscOptionsObject)) {
800     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)));
801   }
802   PetscFunctionReturn(PETSC_SUCCESS);
803 }
804 
805 PetscErrorCode PetscOptionsScalar_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], PetscScalar currentvalue, PetscScalar *value, PetscBool *set)
806 {
807   PetscFunctionBegin;
808 #if !defined(PETSC_USE_COMPLEX)
809   PetscCall(PetscOptionsReal(opt, text, man, currentvalue, value, set));
810 #else
811   PetscCall(PetscOptionsGetScalar(PetscOptionsObject->options, PetscOptionsObject->prefix, opt, value, set));
812 #endif
813   PetscFunctionReturn(PETSC_SUCCESS);
814 }
815 
816 PetscErrorCode PetscOptionsName_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], PetscBool *flg)
817 {
818   const char *prefix = PetscOptionsObject->prefix;
819 
820   PetscFunctionBegin;
821   PetscAssertPointer(opt, 2);
822   PetscAssertPointer(flg, 5);
823   if (!PetscOptionsObject->count) {
824     PetscOptionItem amsopt;
825 
826     PetscCall(PetscOptionItemCreate_Private(PetscOptionsObject, opt, text, man, OPTION_BOOL, &amsopt));
827     PetscCall(PetscMalloc(sizeof(PetscBool), &amsopt->data));
828 
829     *(PetscBool *)amsopt->data = PETSC_FALSE;
830   }
831   PetscCall(PetscOptionsHasName(PetscOptionsObject->options, prefix, opt, flg));
832   if (ShouldPrintHelp(PetscOptionsObject)) PetscCall((*PetscHelpPrintf)(PetscOptionsObject->comm, "  -%s%s: %s (%s)\n", Prefix(prefix), opt + 1, text, ManSection(man)));
833   PetscFunctionReturn(PETSC_SUCCESS);
834 }
835 
836 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)
837 {
838   const char *prefix = PetscOptionsObject->prefix;
839   PetscBool   lset;
840 
841   PetscFunctionBegin;
842   PetscAssertPointer(opt, 2);
843   PetscAssertPointer(value, 7);
844   if (set) PetscAssertPointer(set, 9);
845   if (!PetscOptionsObject->count) {
846     PetscOptionItem amsopt;
847 
848     PetscCall(PetscOptionItemCreate_Private(PetscOptionsObject, opt, ltext, man, OPTION_FLIST, &amsopt));
849     /* must use system malloc since SAWs may free this */
850     PetscCall(PetscStrdup(currentvalue ? currentvalue : "", (char **)&amsopt->data));
851     amsopt->flist = list;
852   }
853   PetscCall(PetscOptionsGetString(PetscOptionsObject->options, prefix, opt, value, len, &lset));
854   if (set) *set = lset;
855   if (ShouldPrintHelp(PetscOptionsObject)) PetscCall(PetscFunctionListPrintTypes(PetscOptionsObject->comm, stdout, Prefix(prefix), opt, ltext, man, list, currentvalue, lset ? value : currentvalue));
856   PetscFunctionReturn(PETSC_SUCCESS);
857 }
858 
859 #ifdef __cplusplus
860   #include <type_traits>
861 #endif
862 
863 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)
864 {
865   const char *prefix = PetscOptionsObject->prefix;
866   PetscBool   lset;
867 
868   PetscFunctionBegin;
869   PetscAssertPointer(opt, 2);
870   PetscAssertPointer(value, 8);
871   if (set) PetscAssertPointer(set, 9);
872   if (!PetscOptionsObject->count) {
873     PetscOptionItem amsopt;
874 
875     PetscCall(PetscOptionItemCreate_Private(PetscOptionsObject, opt, ltext, man, OPTION_ELIST, &amsopt));
876     /* must use system malloc since SAWs may free this */
877     PetscCall(PetscStrdup(currentvalue ? currentvalue : "", (char **)&amsopt->data));
878     PetscCall(PetscStrNArrayallocpy(ntext, list, (char ***)&amsopt->list));
879     PetscCheck(ntext <= CHAR_MAX, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of list entries %" PetscInt_FMT " > %d", ntext, CHAR_MAX);
880 #ifdef __cplusplus
881     static_assert(std::is_same<typename std::decay<decltype(amsopt->nlist)>::type, char>::value, "");
882 #endif
883     amsopt->nlist = (char)ntext;
884   }
885   PetscCall(PetscOptionsGetEList(PetscOptionsObject->options, prefix, opt, list, ntext, value, &lset));
886   if (set) *set = lset;
887   if (ShouldPrintHelp(PetscOptionsObject)) {
888     const MPI_Comm comm = PetscOptionsObject->comm;
889 
890     PetscCall((*PetscHelpPrintf)(comm, "  -%s%s: <now %s : formerly %s> %s (choose one of)", Prefix(prefix), opt + 1, lset ? list[*value] : currentvalue, currentvalue, ltext));
891     for (PetscInt i = 0; i < ntext; ++i) PetscCall((*PetscHelpPrintf)(comm, " %s", list[i]));
892     PetscCall((*PetscHelpPrintf)(comm, " (%s)\n", ManSection(man)));
893   }
894   PetscFunctionReturn(PETSC_SUCCESS);
895 }
896 
897 PetscErrorCode PetscOptionsBoolGroupBegin_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], PetscBool *flg)
898 {
899   const char *prefix = PetscOptionsObject->prefix;
900 
901   PetscFunctionBegin;
902   PetscAssertPointer(opt, 2);
903   PetscAssertPointer(flg, 5);
904   if (!PetscOptionsObject->count) {
905     PetscOptionItem amsopt;
906 
907     PetscCall(PetscOptionItemCreate_Private(PetscOptionsObject, opt, text, man, OPTION_BOOL, &amsopt));
908     PetscCall(PetscMalloc(sizeof(PetscBool), &amsopt->data));
909 
910     *(PetscBool *)amsopt->data = PETSC_FALSE;
911   }
912   *flg = PETSC_FALSE;
913   PetscCall(PetscOptionsGetBool(PetscOptionsObject->options, prefix, opt, flg, NULL));
914   if (ShouldPrintHelp(PetscOptionsObject)) {
915     const MPI_Comm comm = PetscOptionsObject->comm;
916 
917     PetscCall((*PetscHelpPrintf)(comm, "  Pick at most one of -------------\n"));
918     PetscCall((*PetscHelpPrintf)(comm, "    -%s%s: %s (%s)\n", Prefix(prefix), opt + 1, text, ManSection(man)));
919   }
920   PetscFunctionReturn(PETSC_SUCCESS);
921 }
922 
923 PetscErrorCode PetscOptionsBoolGroup_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], PetscBool *flg)
924 {
925   const char *prefix = PetscOptionsObject->prefix;
926 
927   PetscFunctionBegin;
928   PetscAssertPointer(opt, 2);
929   PetscAssertPointer(flg, 5);
930   if (!PetscOptionsObject->count) {
931     PetscOptionItem amsopt;
932 
933     PetscCall(PetscOptionItemCreate_Private(PetscOptionsObject, opt, text, man, OPTION_BOOL, &amsopt));
934     PetscCall(PetscMalloc(sizeof(PetscBool), &amsopt->data));
935 
936     *(PetscBool *)amsopt->data = PETSC_FALSE;
937   }
938   *flg = PETSC_FALSE;
939   PetscCall(PetscOptionsGetBool(PetscOptionsObject->options, prefix, opt, flg, NULL));
940   if (ShouldPrintHelp(PetscOptionsObject)) PetscCall((*PetscHelpPrintf)(PetscOptionsObject->comm, "    -%s%s: %s (%s)\n", Prefix(prefix), opt + 1, text, ManSection(man)));
941   PetscFunctionReturn(PETSC_SUCCESS);
942 }
943 
944 PetscErrorCode PetscOptionsBoolGroupEnd_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], PetscBool *flg)
945 {
946   const char *prefix = PetscOptionsObject->prefix;
947 
948   PetscFunctionBegin;
949   PetscAssertPointer(opt, 2);
950   PetscAssertPointer(flg, 5);
951   if (!PetscOptionsObject->count) {
952     PetscOptionItem amsopt;
953 
954     PetscCall(PetscOptionItemCreate_Private(PetscOptionsObject, opt, text, man, OPTION_BOOL, &amsopt));
955     PetscCall(PetscMalloc(sizeof(PetscBool), &amsopt->data));
956 
957     *(PetscBool *)amsopt->data = PETSC_FALSE;
958   }
959   *flg = PETSC_FALSE;
960   PetscCall(PetscOptionsGetBool(PetscOptionsObject->options, prefix, opt, flg, NULL));
961   if (ShouldPrintHelp(PetscOptionsObject)) PetscCall((*PetscHelpPrintf)(PetscOptionsObject->comm, "    -%s%s: %s (%s)\n", Prefix(prefix), opt + 1, text, ManSection(man)));
962   PetscFunctionReturn(PETSC_SUCCESS);
963 }
964 
965 PetscErrorCode PetscOptionsBool_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], PetscBool currentvalue, PetscBool *flg, PetscBool *set)
966 {
967   const char *prefix = PetscOptionsObject->prefix;
968   PetscBool   iset;
969 
970   PetscFunctionBegin;
971   PetscAssertPointer(opt, 2);
972   PetscAssertPointer(flg, 6);
973   if (set) PetscAssertPointer(set, 7);
974   if (!PetscOptionsObject->count) {
975     PetscOptionItem amsopt;
976 
977     PetscCall(PetscOptionItemCreate_Private(PetscOptionsObject, opt, text, man, OPTION_BOOL, &amsopt));
978     PetscCall(PetscMalloc(sizeof(PetscBool), &amsopt->data));
979 
980     *(PetscBool *)amsopt->data = currentvalue;
981   }
982   PetscCall(PetscOptionsGetBool(PetscOptionsObject->options, prefix, opt, flg, &iset));
983   if (set) *set = iset;
984   if (ShouldPrintHelp(PetscOptionsObject)) {
985     const char *curvalue = PetscBools[currentvalue];
986 
987     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)));
988   }
989   PetscFunctionReturn(PETSC_SUCCESS);
990 }
991 
992 PetscErrorCode PetscOptionsRealArray_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], PetscReal value[], PetscInt *n, PetscBool *set)
993 {
994   const char *prefix = PetscOptionsObject->prefix;
995 
996   PetscFunctionBegin;
997   PetscAssertPointer(opt, 2);
998   PetscAssertPointer(n, 6);
999   PetscCheck(*n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "n (%" PetscInt_FMT ") cannot be negative", *n);
1000   if (*n) PetscAssertPointer(value, 5);
1001   if (set) PetscAssertPointer(set, 7);
1002   if (!PetscOptionsObject->count) {
1003     const PetscInt  nv = *n;
1004     PetscReal      *vals;
1005     PetscOptionItem amsopt;
1006 
1007     PetscCall(PetscOptionItemCreate_Private(PetscOptionsObject, opt, text, man, OPTION_REAL_ARRAY, &amsopt));
1008     PetscCall(PetscMalloc(nv * sizeof(*vals), &vals));
1009     for (PetscInt i = 0; i < nv; ++i) vals[i] = value[i];
1010     amsopt->arraylength = nv;
1011     amsopt->data        = vals;
1012   }
1013   PetscCall(PetscOptionsGetRealArray(PetscOptionsObject->options, prefix, opt, value, n, set));
1014   if (ShouldPrintHelp(PetscOptionsObject)) {
1015     const PetscInt nv   = *n;
1016     const MPI_Comm comm = PetscOptionsObject->comm;
1017 
1018     PetscCall((*PetscHelpPrintf)(comm, "  -%s%s: <%g", Prefix(prefix), opt + 1, (double)value[0]));
1019     for (PetscInt i = 1; i < nv; ++i) PetscCall((*PetscHelpPrintf)(comm, ",%g", (double)value[i]));
1020     PetscCall((*PetscHelpPrintf)(comm, ">: %s (%s)\n", text, ManSection(man)));
1021   }
1022   PetscFunctionReturn(PETSC_SUCCESS);
1023 }
1024 
1025 PetscErrorCode PetscOptionsScalarArray_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], PetscScalar value[], PetscInt *n, PetscBool *set)
1026 {
1027   const char *prefix = PetscOptionsObject->prefix;
1028 
1029   PetscFunctionBegin;
1030   PetscAssertPointer(opt, 2);
1031   PetscAssertPointer(n, 6);
1032   PetscCheck(*n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "n (%" PetscInt_FMT ") cannot be negative", *n);
1033   if (*n) PetscAssertPointer(value, 5);
1034   if (set) PetscAssertPointer(set, 7);
1035   if (!PetscOptionsObject->count) {
1036     const PetscInt  nv = *n;
1037     PetscOptionItem amsopt;
1038     PetscScalar    *vals;
1039 
1040     PetscCall(PetscOptionItemCreate_Private(PetscOptionsObject, opt, text, man, OPTION_SCALAR_ARRAY, &amsopt));
1041     PetscCall(PetscMalloc(nv * sizeof(*vals), &vals));
1042     for (PetscInt i = 0; i < nv; ++i) vals[i] = value[i];
1043     amsopt->arraylength = nv;
1044     amsopt->data        = vals;
1045   }
1046   PetscCall(PetscOptionsGetScalarArray(PetscOptionsObject->options, prefix, opt, value, n, set));
1047   if (ShouldPrintHelp(PetscOptionsObject)) {
1048     const PetscInt nv   = *n;
1049     const MPI_Comm comm = PetscOptionsObject->comm;
1050 
1051     PetscCall((*PetscHelpPrintf)(comm, "  -%s%s: <%g+%gi", Prefix(prefix), opt + 1, (double)PetscRealPart(value[0]), (double)PetscImaginaryPart(value[0])));
1052     for (PetscInt i = 1; i < nv; ++i) PetscCall((*PetscHelpPrintf)(comm, ",%g+%gi", (double)PetscRealPart(value[i]), (double)PetscImaginaryPart(value[i])));
1053     PetscCall((*PetscHelpPrintf)(comm, ">: %s (%s)\n", text, ManSection(man)));
1054   }
1055   PetscFunctionReturn(PETSC_SUCCESS);
1056 }
1057 
1058 PetscErrorCode PetscOptionsIntArray_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], PetscInt value[], PetscInt *n, PetscBool *set)
1059 {
1060   const char *prefix = PetscOptionsObject->prefix;
1061 
1062   PetscFunctionBegin;
1063   PetscAssertPointer(opt, 2);
1064   PetscAssertPointer(n, 6);
1065   PetscCheck(*n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "n (%" PetscInt_FMT ") cannot be negative", *n);
1066   if (*n) PetscAssertPointer(value, 5);
1067   if (set) PetscAssertPointer(set, 7);
1068   if (!PetscOptionsObject->count) {
1069     const PetscInt  nv = *n;
1070     PetscInt       *vals;
1071     PetscOptionItem amsopt;
1072 
1073     PetscCall(PetscOptionItemCreate_Private(PetscOptionsObject, opt, text, man, OPTION_INT_ARRAY, &amsopt));
1074     PetscCall(PetscMalloc1(nv, &vals));
1075     for (PetscInt i = 0; i < nv; ++i) vals[i] = value[i];
1076     amsopt->arraylength = nv;
1077     amsopt->data        = vals;
1078   }
1079   PetscCall(PetscOptionsGetIntArray(PetscOptionsObject->options, prefix, opt, value, n, set));
1080   if (ShouldPrintHelp(PetscOptionsObject)) {
1081     const PetscInt nv   = *n;
1082     const MPI_Comm comm = PetscOptionsObject->comm;
1083 
1084     PetscCall((*PetscHelpPrintf)(comm, "  -%s%s: <%" PetscInt_FMT, Prefix(prefix), opt + 1, value[0]));
1085     for (PetscInt i = 1; i < nv; ++i) PetscCall((*PetscHelpPrintf)(comm, ",%" PetscInt_FMT, value[i]));
1086     PetscCall((*PetscHelpPrintf)(comm, ">: %s (%s)\n", text, ManSection(man)));
1087   }
1088   PetscFunctionReturn(PETSC_SUCCESS);
1089 }
1090 
1091 PetscErrorCode PetscOptionsStringArray_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], char *value[], PetscInt *nmax, PetscBool *set)
1092 {
1093   const char *prefix = PetscOptionsObject->prefix;
1094 
1095   PetscFunctionBegin;
1096   PetscAssertPointer(opt, 2);
1097   PetscAssertPointer(nmax, 6);
1098   PetscCheck(*nmax >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "n (%" PetscInt_FMT ") cannot be negative", *nmax);
1099   if (*nmax) PetscAssertPointer(value, 5);
1100   if (set) PetscAssertPointer(set, 7);
1101   if (!PetscOptionsObject->count) {
1102     const PetscInt  nmaxv = *nmax;
1103     PetscOptionItem amsopt;
1104 
1105     PetscCall(PetscOptionItemCreate_Private(PetscOptionsObject, opt, text, man, OPTION_STRING_ARRAY, &amsopt));
1106     PetscCall(PetscMalloc1(nmaxv, (char **)&amsopt->data));
1107     amsopt->arraylength = nmaxv;
1108   }
1109   PetscCall(PetscOptionsGetStringArray(PetscOptionsObject->options, prefix, opt, value, nmax, set));
1110   if (ShouldPrintHelp(PetscOptionsObject)) PetscCall((*PetscHelpPrintf)(PetscOptionsObject->comm, "  -%s%s: <string1,string2,...>: %s (%s)\n", Prefix(prefix), opt + 1, text, ManSection(man)));
1111   PetscFunctionReturn(PETSC_SUCCESS);
1112 }
1113 
1114 PetscErrorCode PetscOptionsBoolArray_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], PetscBool value[], PetscInt *n, PetscBool *set)
1115 {
1116   const char *prefix = PetscOptionsObject->prefix;
1117 
1118   PetscFunctionBegin;
1119   PetscAssertPointer(opt, 2);
1120   PetscAssertPointer(n, 6);
1121   PetscCheck(*n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "n (%" PetscInt_FMT ") cannot be negative", *n);
1122   if (*n) PetscAssertPointer(value, 5);
1123   if (set) PetscAssertPointer(set, 7);
1124   if (!PetscOptionsObject->count) {
1125     const PetscInt  nv = *n;
1126     PetscBool      *vals;
1127     PetscOptionItem amsopt;
1128 
1129     PetscCall(PetscOptionItemCreate_Private(PetscOptionsObject, opt, text, man, OPTION_BOOL_ARRAY, &amsopt));
1130     PetscCall(PetscMalloc1(nv, &vals));
1131     for (PetscInt i = 0; i < nv; ++i) vals[i] = value[i];
1132     amsopt->arraylength = nv;
1133     amsopt->data        = vals;
1134   }
1135   PetscCall(PetscOptionsGetBoolArray(PetscOptionsObject->options, prefix, opt, value, n, set));
1136   if (ShouldPrintHelp(PetscOptionsObject)) {
1137     const PetscInt nv   = *n;
1138     const MPI_Comm comm = PetscOptionsObject->comm;
1139 
1140     PetscCall((*PetscHelpPrintf)(comm, "  -%s%s: <%d", Prefix(prefix), opt + 1, value[0]));
1141     for (PetscInt i = 1; i < nv; ++i) PetscCall((*PetscHelpPrintf)(comm, ",%d", value[i]));
1142     PetscCall((*PetscHelpPrintf)(comm, ">: %s (%s)\n", text, ManSection(man)));
1143   }
1144   PetscFunctionReturn(PETSC_SUCCESS);
1145 }
1146 
1147 /*MC
1148   PetscOptionsViewer - Creates a viewer appropriate for the type indicated by the user
1149 
1150   Synopsis:
1151   #include <petscviewer.h>
1152   PetscErrorCode PetscOptionsViewer(const char opt[], const char text[], const char man[], PetscViewer *viewer, PetscViewerFormat *format, PetscBool *set)
1153 
1154   Logically Collective on the communicator passed in `PetscOptionsBegin()`
1155 
1156   Input Parameters:
1157 + opt  - option name
1158 . text - short string that describes the option
1159 - man  - manual page with additional information on option
1160 
1161   Output Parameters:
1162 + viewer - the viewer
1163 . format - the PetscViewerFormat requested by the user, pass `NULL` if not needed
1164 - set    - `PETSC_TRUE` if found, else `PETSC_FALSE`
1165 
1166   Level: beginner
1167 
1168   Notes:
1169   Must be between a `PetscOptionsBegin()` and a `PetscOptionsEnd()`
1170 
1171   See `PetscOptionsCreateViewer()` for the format of the supplied viewer and its options
1172 
1173 .seealso: `PetscOptionsCreateViewer()`, `PetscOptionsHasName()`, `PetscOptionsGetString()`, `PetscOptionsGetInt()`,
1174           `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()`
1175           `PetscOptionsInt()`, `PetscOptionsString()`, `PetscOptionsReal()`,
1176           `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
1177           `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
1178           `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
1179           `PetscOptionsFList()`, `PetscOptionsEList()`
1180 M*/
1181 PetscErrorCode PetscOptionsViewer_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], PetscViewer *viewer, PetscViewerFormat *format, PetscBool *set)
1182 {
1183   const MPI_Comm comm   = PetscOptionsObject->comm;
1184   const char    *prefix = PetscOptionsObject->prefix;
1185 
1186   PetscFunctionBegin;
1187   PetscAssertPointer(opt, 2);
1188   PetscAssertPointer(viewer, 5);
1189   if (format) PetscAssertPointer(format, 6);
1190   if (set) PetscAssertPointer(set, 7);
1191   if (!PetscOptionsObject->count) {
1192     PetscOptionItem amsopt;
1193 
1194     PetscCall(PetscOptionItemCreate_Private(PetscOptionsObject, opt, text, man, OPTION_STRING, &amsopt));
1195     /* must use system malloc since SAWs may free this */
1196     PetscCall(PetscStrdup("", (char **)&amsopt->data));
1197   }
1198   PetscCall(PetscOptionsCreateViewer(comm, PetscOptionsObject->options, prefix, opt, viewer, format, set));
1199   if (ShouldPrintHelp(PetscOptionsObject)) PetscCall((*PetscHelpPrintf)(comm, "  -%s%s: <%s>: %s (%s)\n", Prefix(prefix), opt + 1, "", text, ManSection(man)));
1200   PetscFunctionReturn(PETSC_SUCCESS);
1201 }
1202