xref: /petsc/src/sys/objects/aoptions.c (revision af27ebaa0199971c43fd2e2e162251afd1bcda49)
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   size_t          i;
338 
339   PetscFunctionBegin;
340   PetscCall((*PetscPrintf)(PETSC_COMM_WORLD, "%s --------------------\n", PetscOptionsObject->title));
341   while (next) {
342     switch (next->type) {
343     case OPTION_HEAD:
344       break;
345     case OPTION_INT_ARRAY:
346       PetscCall(PetscPrintf(PETSC_COMM_WORLD, "-%s%s: <", PetscOptionsObject->prefix ? PetscOptionsObject->prefix : "", next->option + 1));
347       vald = (PetscInt *)next->data;
348       for (i = 0; i < next->arraylength; i++) {
349         PetscCall(PetscPrintf(PETSC_COMM_WORLD, "%" PetscInt_FMT, vald[i]));
350         if (i < next->arraylength - 1) PetscCall(PetscPrintf(PETSC_COMM_WORLD, ","));
351       }
352       PetscCall(PetscPrintf(PETSC_COMM_WORLD, ">: %s (%s) ", next->text, next->man));
353       PetscCall(PetscScanString(PETSC_COMM_WORLD, 512, str));
354       if (str[0]) {
355         PetscToken token;
356         PetscInt   n = 0, nmax = next->arraylength, *dvalue = (PetscInt *)next->data, start, end;
357         size_t     len;
358         char      *value;
359         PetscBool  foundrange;
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 < len; i++) {
374             if (value[i] == '-') {
375               PetscCheck(i != 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 (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 PetscOptionsString_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], const char currentvalue[], char value[], size_t len, PetscBool *set)
722 {
723   const char *prefix = PetscOptionsObject->prefix;
724   PetscBool   lset;
725 
726   PetscFunctionBegin;
727   PetscAssertPointer(opt, 2);
728   PetscAssertPointer(value, 6);
729   if (set) PetscAssertPointer(set, 8);
730   if (!PetscOptionsObject->count) {
731     PetscOptionItem amsopt;
732 
733     PetscCall(PetscOptionItemCreate_Private(PetscOptionsObject, opt, text, man, OPTION_STRING, &amsopt));
734     /* must use system malloc since SAWs may free this */
735     PetscCall(PetscStrdup(currentvalue ? currentvalue : "", (char **)&amsopt->data));
736   }
737   PetscCall(PetscOptionsGetString(PetscOptionsObject->options, prefix, opt, value, len, &lset));
738   if (set) *set = lset;
739   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)));
740   PetscFunctionReturn(PETSC_SUCCESS);
741 }
742 
743 PetscErrorCode PetscOptionsReal_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], PetscReal currentvalue, PetscReal *value, PetscBool *set)
744 {
745   const char *prefix = PetscOptionsObject->prefix;
746   PetscBool   lset;
747 
748   PetscFunctionBegin;
749   PetscAssertPointer(opt, 2);
750   PetscAssertPointer(value, 6);
751   if (set) PetscAssertPointer(set, 7);
752   if (!PetscOptionsObject->count) {
753     PetscOptionItem amsopt;
754 
755     PetscCall(PetscOptionItemCreate_Private(PetscOptionsObject, opt, text, man, OPTION_REAL, &amsopt));
756     PetscCall(PetscMalloc(sizeof(PetscReal), &amsopt->data));
757 
758     *(PetscReal *)amsopt->data = currentvalue;
759   }
760   PetscCall(PetscOptionsGetReal(PetscOptionsObject->options, prefix, opt, value, &lset));
761   if (set) *set = lset;
762   if (ShouldPrintHelp(PetscOptionsObject)) {
763     PetscCall((*PetscHelpPrintf)(PetscOptionsObject->comm, "  -%s%s: <now %g : formerly %g>: %s (%s)\n", Prefix(prefix), opt + 1, lset ? (double)*value : (double)currentvalue, (double)currentvalue, text, ManSection(man)));
764   }
765   PetscFunctionReturn(PETSC_SUCCESS);
766 }
767 
768 PetscErrorCode PetscOptionsScalar_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], PetscScalar currentvalue, PetscScalar *value, PetscBool *set)
769 {
770   PetscFunctionBegin;
771 #if !defined(PETSC_USE_COMPLEX)
772   PetscCall(PetscOptionsReal(opt, text, man, currentvalue, value, set));
773 #else
774   PetscCall(PetscOptionsGetScalar(PetscOptionsObject->options, PetscOptionsObject->prefix, opt, value, set));
775 #endif
776   PetscFunctionReturn(PETSC_SUCCESS);
777 }
778 
779 PetscErrorCode PetscOptionsName_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], PetscBool *flg)
780 {
781   const char *prefix = PetscOptionsObject->prefix;
782 
783   PetscFunctionBegin;
784   PetscAssertPointer(opt, 2);
785   PetscAssertPointer(flg, 5);
786   if (!PetscOptionsObject->count) {
787     PetscOptionItem amsopt;
788 
789     PetscCall(PetscOptionItemCreate_Private(PetscOptionsObject, opt, text, man, OPTION_BOOL, &amsopt));
790     PetscCall(PetscMalloc(sizeof(PetscBool), &amsopt->data));
791 
792     *(PetscBool *)amsopt->data = PETSC_FALSE;
793   }
794   PetscCall(PetscOptionsHasName(PetscOptionsObject->options, prefix, opt, flg));
795   if (ShouldPrintHelp(PetscOptionsObject)) PetscCall((*PetscHelpPrintf)(PetscOptionsObject->comm, "  -%s%s: %s (%s)\n", Prefix(prefix), opt + 1, text, ManSection(man)));
796   PetscFunctionReturn(PETSC_SUCCESS);
797 }
798 
799 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)
800 {
801   const char *prefix = PetscOptionsObject->prefix;
802   PetscBool   lset;
803 
804   PetscFunctionBegin;
805   PetscAssertPointer(opt, 2);
806   PetscAssertPointer(value, 7);
807   if (set) PetscAssertPointer(set, 9);
808   if (!PetscOptionsObject->count) {
809     PetscOptionItem amsopt;
810 
811     PetscCall(PetscOptionItemCreate_Private(PetscOptionsObject, opt, ltext, man, OPTION_FLIST, &amsopt));
812     /* must use system malloc since SAWs may free this */
813     PetscCall(PetscStrdup(currentvalue ? currentvalue : "", (char **)&amsopt->data));
814     amsopt->flist = list;
815   }
816   PetscCall(PetscOptionsGetString(PetscOptionsObject->options, prefix, opt, value, len, &lset));
817   if (set) *set = lset;
818   if (ShouldPrintHelp(PetscOptionsObject)) PetscCall(PetscFunctionListPrintTypes(PetscOptionsObject->comm, stdout, Prefix(prefix), opt, ltext, man, list, currentvalue, lset ? value : currentvalue));
819   PetscFunctionReturn(PETSC_SUCCESS);
820 }
821 
822 #ifdef __cplusplus
823   #include <type_traits>
824 #endif
825 
826 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)
827 {
828   const char *prefix = PetscOptionsObject->prefix;
829   PetscBool   lset;
830 
831   PetscFunctionBegin;
832   PetscAssertPointer(opt, 2);
833   PetscAssertPointer(value, 8);
834   if (set) PetscAssertPointer(set, 9);
835   if (!PetscOptionsObject->count) {
836     PetscOptionItem amsopt;
837 
838     PetscCall(PetscOptionItemCreate_Private(PetscOptionsObject, opt, ltext, man, OPTION_ELIST, &amsopt));
839     /* must use system malloc since SAWs may free this */
840     PetscCall(PetscStrdup(currentvalue ? currentvalue : "", (char **)&amsopt->data));
841     PetscCall(PetscStrNArrayallocpy(ntext, list, (char ***)&amsopt->list));
842     PetscCheck(ntext <= CHAR_MAX, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of list entries %" PetscInt_FMT " > %d", ntext, CHAR_MAX);
843 #ifdef __cplusplus
844     static_assert(std::is_same<typename std::decay<decltype(amsopt->nlist)>::type, char>::value, "");
845 #endif
846     amsopt->nlist = (char)ntext;
847   }
848   PetscCall(PetscOptionsGetEList(PetscOptionsObject->options, prefix, opt, list, ntext, value, &lset));
849   if (set) *set = lset;
850   if (ShouldPrintHelp(PetscOptionsObject)) {
851     const MPI_Comm comm = PetscOptionsObject->comm;
852 
853     PetscCall((*PetscHelpPrintf)(comm, "  -%s%s: <now %s : formerly %s> %s (choose one of)", Prefix(prefix), opt + 1, lset ? list[*value] : currentvalue, currentvalue, ltext));
854     for (PetscInt i = 0; i < ntext; ++i) PetscCall((*PetscHelpPrintf)(comm, " %s", list[i]));
855     PetscCall((*PetscHelpPrintf)(comm, " (%s)\n", ManSection(man)));
856   }
857   PetscFunctionReturn(PETSC_SUCCESS);
858 }
859 
860 PetscErrorCode PetscOptionsBoolGroupBegin_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], PetscBool *flg)
861 {
862   const char *prefix = PetscOptionsObject->prefix;
863 
864   PetscFunctionBegin;
865   PetscAssertPointer(opt, 2);
866   PetscAssertPointer(flg, 5);
867   if (!PetscOptionsObject->count) {
868     PetscOptionItem amsopt;
869 
870     PetscCall(PetscOptionItemCreate_Private(PetscOptionsObject, opt, text, man, OPTION_BOOL, &amsopt));
871     PetscCall(PetscMalloc(sizeof(PetscBool), &amsopt->data));
872 
873     *(PetscBool *)amsopt->data = PETSC_FALSE;
874   }
875   *flg = PETSC_FALSE;
876   PetscCall(PetscOptionsGetBool(PetscOptionsObject->options, prefix, opt, flg, NULL));
877   if (ShouldPrintHelp(PetscOptionsObject)) {
878     const MPI_Comm comm = PetscOptionsObject->comm;
879 
880     PetscCall((*PetscHelpPrintf)(comm, "  Pick at most one of -------------\n"));
881     PetscCall((*PetscHelpPrintf)(comm, "    -%s%s: %s (%s)\n", Prefix(prefix), opt + 1, text, ManSection(man)));
882   }
883   PetscFunctionReturn(PETSC_SUCCESS);
884 }
885 
886 PetscErrorCode PetscOptionsBoolGroup_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], PetscBool *flg)
887 {
888   const char *prefix = PetscOptionsObject->prefix;
889 
890   PetscFunctionBegin;
891   PetscAssertPointer(opt, 2);
892   PetscAssertPointer(flg, 5);
893   if (!PetscOptionsObject->count) {
894     PetscOptionItem amsopt;
895 
896     PetscCall(PetscOptionItemCreate_Private(PetscOptionsObject, opt, text, man, OPTION_BOOL, &amsopt));
897     PetscCall(PetscMalloc(sizeof(PetscBool), &amsopt->data));
898 
899     *(PetscBool *)amsopt->data = PETSC_FALSE;
900   }
901   *flg = PETSC_FALSE;
902   PetscCall(PetscOptionsGetBool(PetscOptionsObject->options, prefix, opt, flg, NULL));
903   if (ShouldPrintHelp(PetscOptionsObject)) PetscCall((*PetscHelpPrintf)(PetscOptionsObject->comm, "    -%s%s: %s (%s)\n", Prefix(prefix), opt + 1, text, ManSection(man)));
904   PetscFunctionReturn(PETSC_SUCCESS);
905 }
906 
907 PetscErrorCode PetscOptionsBoolGroupEnd_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], PetscBool *flg)
908 {
909   const char *prefix = PetscOptionsObject->prefix;
910 
911   PetscFunctionBegin;
912   PetscAssertPointer(opt, 2);
913   PetscAssertPointer(flg, 5);
914   if (!PetscOptionsObject->count) {
915     PetscOptionItem amsopt;
916 
917     PetscCall(PetscOptionItemCreate_Private(PetscOptionsObject, opt, text, man, OPTION_BOOL, &amsopt));
918     PetscCall(PetscMalloc(sizeof(PetscBool), &amsopt->data));
919 
920     *(PetscBool *)amsopt->data = PETSC_FALSE;
921   }
922   *flg = PETSC_FALSE;
923   PetscCall(PetscOptionsGetBool(PetscOptionsObject->options, prefix, opt, flg, NULL));
924   if (ShouldPrintHelp(PetscOptionsObject)) PetscCall((*PetscHelpPrintf)(PetscOptionsObject->comm, "    -%s%s: %s (%s)\n", Prefix(prefix), opt + 1, text, ManSection(man)));
925   PetscFunctionReturn(PETSC_SUCCESS);
926 }
927 
928 PetscErrorCode PetscOptionsBool_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], PetscBool currentvalue, PetscBool *flg, PetscBool *set)
929 {
930   const char *prefix = PetscOptionsObject->prefix;
931   PetscBool   iset;
932 
933   PetscFunctionBegin;
934   PetscAssertPointer(opt, 2);
935   PetscAssertPointer(flg, 6);
936   if (set) PetscAssertPointer(set, 7);
937   if (!PetscOptionsObject->count) {
938     PetscOptionItem amsopt;
939 
940     PetscCall(PetscOptionItemCreate_Private(PetscOptionsObject, opt, text, man, OPTION_BOOL, &amsopt));
941     PetscCall(PetscMalloc(sizeof(PetscBool), &amsopt->data));
942 
943     *(PetscBool *)amsopt->data = currentvalue;
944   }
945   PetscCall(PetscOptionsGetBool(PetscOptionsObject->options, prefix, opt, flg, &iset));
946   if (set) *set = iset;
947   if (ShouldPrintHelp(PetscOptionsObject)) {
948     const char *curvalue = PetscBools[currentvalue];
949 
950     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)));
951   }
952   PetscFunctionReturn(PETSC_SUCCESS);
953 }
954 
955 PetscErrorCode PetscOptionsRealArray_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], PetscReal value[], PetscInt *n, PetscBool *set)
956 {
957   const char *prefix = PetscOptionsObject->prefix;
958 
959   PetscFunctionBegin;
960   PetscAssertPointer(opt, 2);
961   PetscAssertPointer(n, 6);
962   PetscCheck(*n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "n (%" PetscInt_FMT ") cannot be negative", *n);
963   if (*n) PetscAssertPointer(value, 5);
964   if (set) PetscAssertPointer(set, 7);
965   if (!PetscOptionsObject->count) {
966     const PetscInt  nv = *n;
967     PetscReal      *vals;
968     PetscOptionItem amsopt;
969 
970     PetscCall(PetscOptionItemCreate_Private(PetscOptionsObject, opt, text, man, OPTION_REAL_ARRAY, &amsopt));
971     PetscCall(PetscMalloc(nv * sizeof(*vals), &vals));
972     for (PetscInt i = 0; i < nv; ++i) vals[i] = value[i];
973     amsopt->arraylength = nv;
974     amsopt->data        = vals;
975   }
976   PetscCall(PetscOptionsGetRealArray(PetscOptionsObject->options, prefix, opt, value, n, set));
977   if (ShouldPrintHelp(PetscOptionsObject)) {
978     const PetscInt nv   = *n;
979     const MPI_Comm comm = PetscOptionsObject->comm;
980 
981     PetscCall((*PetscHelpPrintf)(comm, "  -%s%s: <%g", Prefix(prefix), opt + 1, (double)value[0]));
982     for (PetscInt i = 1; i < nv; ++i) PetscCall((*PetscHelpPrintf)(comm, ",%g", (double)value[i]));
983     PetscCall((*PetscHelpPrintf)(comm, ">: %s (%s)\n", text, ManSection(man)));
984   }
985   PetscFunctionReturn(PETSC_SUCCESS);
986 }
987 
988 PetscErrorCode PetscOptionsScalarArray_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], PetscScalar value[], PetscInt *n, PetscBool *set)
989 {
990   const char *prefix = PetscOptionsObject->prefix;
991 
992   PetscFunctionBegin;
993   PetscAssertPointer(opt, 2);
994   PetscAssertPointer(n, 6);
995   PetscCheck(*n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "n (%" PetscInt_FMT ") cannot be negative", *n);
996   if (*n) PetscAssertPointer(value, 5);
997   if (set) PetscAssertPointer(set, 7);
998   if (!PetscOptionsObject->count) {
999     const PetscInt  nv = *n;
1000     PetscOptionItem amsopt;
1001     PetscScalar    *vals;
1002 
1003     PetscCall(PetscOptionItemCreate_Private(PetscOptionsObject, opt, text, man, OPTION_SCALAR_ARRAY, &amsopt));
1004     PetscCall(PetscMalloc(nv * sizeof(*vals), &vals));
1005     for (PetscInt i = 0; i < nv; ++i) vals[i] = value[i];
1006     amsopt->arraylength = nv;
1007     amsopt->data        = vals;
1008   }
1009   PetscCall(PetscOptionsGetScalarArray(PetscOptionsObject->options, prefix, opt, value, n, set));
1010   if (ShouldPrintHelp(PetscOptionsObject)) {
1011     const PetscInt nv   = *n;
1012     const MPI_Comm comm = PetscOptionsObject->comm;
1013 
1014     PetscCall((*PetscHelpPrintf)(comm, "  -%s%s: <%g+%gi", Prefix(prefix), opt + 1, (double)PetscRealPart(value[0]), (double)PetscImaginaryPart(value[0])));
1015     for (PetscInt i = 1; i < nv; ++i) PetscCall((*PetscHelpPrintf)(comm, ",%g+%gi", (double)PetscRealPart(value[i]), (double)PetscImaginaryPart(value[i])));
1016     PetscCall((*PetscHelpPrintf)(comm, ">: %s (%s)\n", text, ManSection(man)));
1017   }
1018   PetscFunctionReturn(PETSC_SUCCESS);
1019 }
1020 
1021 PetscErrorCode PetscOptionsIntArray_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], PetscInt value[], PetscInt *n, PetscBool *set)
1022 {
1023   const char *prefix = PetscOptionsObject->prefix;
1024 
1025   PetscFunctionBegin;
1026   PetscAssertPointer(opt, 2);
1027   PetscAssertPointer(n, 6);
1028   PetscCheck(*n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "n (%" PetscInt_FMT ") cannot be negative", *n);
1029   if (*n) PetscAssertPointer(value, 5);
1030   if (set) PetscAssertPointer(set, 7);
1031   if (!PetscOptionsObject->count) {
1032     const PetscInt  nv = *n;
1033     PetscInt       *vals;
1034     PetscOptionItem amsopt;
1035 
1036     PetscCall(PetscOptionItemCreate_Private(PetscOptionsObject, opt, text, man, OPTION_INT_ARRAY, &amsopt));
1037     PetscCall(PetscMalloc1(nv, &vals));
1038     for (PetscInt i = 0; i < nv; ++i) vals[i] = value[i];
1039     amsopt->arraylength = nv;
1040     amsopt->data        = vals;
1041   }
1042   PetscCall(PetscOptionsGetIntArray(PetscOptionsObject->options, prefix, opt, value, n, set));
1043   if (ShouldPrintHelp(PetscOptionsObject)) {
1044     const PetscInt nv   = *n;
1045     const MPI_Comm comm = PetscOptionsObject->comm;
1046 
1047     PetscCall((*PetscHelpPrintf)(comm, "  -%s%s: <%" PetscInt_FMT, Prefix(prefix), opt + 1, value[0]));
1048     for (PetscInt i = 1; i < nv; ++i) PetscCall((*PetscHelpPrintf)(comm, ",%" PetscInt_FMT, value[i]));
1049     PetscCall((*PetscHelpPrintf)(comm, ">: %s (%s)\n", text, ManSection(man)));
1050   }
1051   PetscFunctionReturn(PETSC_SUCCESS);
1052 }
1053 
1054 PetscErrorCode PetscOptionsStringArray_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], char *value[], PetscInt *nmax, PetscBool *set)
1055 {
1056   const char *prefix = PetscOptionsObject->prefix;
1057 
1058   PetscFunctionBegin;
1059   PetscAssertPointer(opt, 2);
1060   PetscAssertPointer(nmax, 6);
1061   PetscCheck(*nmax >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "n (%" PetscInt_FMT ") cannot be negative", *nmax);
1062   if (*nmax) PetscAssertPointer(value, 5);
1063   if (set) PetscAssertPointer(set, 7);
1064   if (!PetscOptionsObject->count) {
1065     const PetscInt  nmaxv = *nmax;
1066     PetscOptionItem amsopt;
1067 
1068     PetscCall(PetscOptionItemCreate_Private(PetscOptionsObject, opt, text, man, OPTION_STRING_ARRAY, &amsopt));
1069     PetscCall(PetscMalloc1(nmaxv, (char **)&amsopt->data));
1070     amsopt->arraylength = nmaxv;
1071   }
1072   PetscCall(PetscOptionsGetStringArray(PetscOptionsObject->options, prefix, opt, value, nmax, set));
1073   if (ShouldPrintHelp(PetscOptionsObject)) PetscCall((*PetscHelpPrintf)(PetscOptionsObject->comm, "  -%s%s: <string1,string2,...>: %s (%s)\n", Prefix(prefix), opt + 1, text, ManSection(man)));
1074   PetscFunctionReturn(PETSC_SUCCESS);
1075 }
1076 
1077 PetscErrorCode PetscOptionsBoolArray_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], PetscBool value[], PetscInt *n, PetscBool *set)
1078 {
1079   const char *prefix = PetscOptionsObject->prefix;
1080 
1081   PetscFunctionBegin;
1082   PetscAssertPointer(opt, 2);
1083   PetscAssertPointer(n, 6);
1084   PetscCheck(*n >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "n (%" PetscInt_FMT ") cannot be negative", *n);
1085   if (*n) PetscAssertPointer(value, 5);
1086   if (set) PetscAssertPointer(set, 7);
1087   if (!PetscOptionsObject->count) {
1088     const PetscInt  nv = *n;
1089     PetscBool      *vals;
1090     PetscOptionItem amsopt;
1091 
1092     PetscCall(PetscOptionItemCreate_Private(PetscOptionsObject, opt, text, man, OPTION_BOOL_ARRAY, &amsopt));
1093     PetscCall(PetscMalloc1(nv, &vals));
1094     for (PetscInt i = 0; i < nv; ++i) vals[i] = value[i];
1095     amsopt->arraylength = nv;
1096     amsopt->data        = vals;
1097   }
1098   PetscCall(PetscOptionsGetBoolArray(PetscOptionsObject->options, prefix, opt, value, n, set));
1099   if (ShouldPrintHelp(PetscOptionsObject)) {
1100     const PetscInt nv   = *n;
1101     const MPI_Comm comm = PetscOptionsObject->comm;
1102 
1103     PetscCall((*PetscHelpPrintf)(comm, "  -%s%s: <%d", Prefix(prefix), opt + 1, value[0]));
1104     for (PetscInt i = 1; i < nv; ++i) PetscCall((*PetscHelpPrintf)(comm, ",%d", value[i]));
1105     PetscCall((*PetscHelpPrintf)(comm, ">: %s (%s)\n", text, ManSection(man)));
1106   }
1107   PetscFunctionReturn(PETSC_SUCCESS);
1108 }
1109 
1110 /*MC
1111   PetscOptionsViewer - Gets a viewer appropriate for the type indicated by the user
1112 
1113   Synopsis:
1114   #include <petscviewer.h>
1115   PetscErrorCode PetscOptionsViewer(const char opt[], const char text[], const char man[], PetscViewer *viewer, PetscViewerFormat *format, PetscBool *set)
1116 
1117   Logically Collective on the communicator passed in `PetscOptionsBegin()`
1118 
1119   Input Parameters:
1120 + opt  - option name
1121 . text - short string that describes the option
1122 - man  - manual page with additional information on option
1123 
1124   Output Parameters:
1125 + viewer - the viewer
1126 . format - the PetscViewerFormat requested by the user, pass NULL if not needed
1127 - set    - `PETSC_TRUE` if found, else `PETSC_FALSE`
1128 
1129   Level: beginner
1130 
1131   Notes:
1132   Must be between a `PetscOptionsBegin()` and a `PetscOptionsEnd()`
1133 
1134   See `PetscOptionsGetViewer()` for the format of the supplied viewer and its options
1135 
1136 .seealso: `PetscOptionsGetViewer()`, `PetscOptionsHasName()`, `PetscOptionsGetString()`, `PetscOptionsGetInt()`,
1137           `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()`
1138           `PetscOptionsInt()`, `PetscOptionsString()`, `PetscOptionsReal()`,
1139           `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`,
1140           `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`,
1141           `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`,
1142           `PetscOptionsFList()`, `PetscOptionsEList()`
1143 M*/
1144 PetscErrorCode PetscOptionsViewer_Private(PetscOptionItems *PetscOptionsObject, const char opt[], const char text[], const char man[], PetscViewer *viewer, PetscViewerFormat *format, PetscBool *set)
1145 {
1146   const MPI_Comm comm   = PetscOptionsObject->comm;
1147   const char    *prefix = PetscOptionsObject->prefix;
1148 
1149   PetscFunctionBegin;
1150   PetscAssertPointer(opt, 2);
1151   PetscAssertPointer(viewer, 5);
1152   if (format) PetscAssertPointer(format, 6);
1153   if (set) PetscAssertPointer(set, 7);
1154   if (!PetscOptionsObject->count) {
1155     PetscOptionItem amsopt;
1156 
1157     PetscCall(PetscOptionItemCreate_Private(PetscOptionsObject, opt, text, man, OPTION_STRING, &amsopt));
1158     /* must use system malloc since SAWs may free this */
1159     PetscCall(PetscStrdup("", (char **)&amsopt->data));
1160   }
1161   PetscCall(PetscOptionsGetViewer(comm, PetscOptionsObject->options, prefix, opt, viewer, format, set));
1162   if (ShouldPrintHelp(PetscOptionsObject)) PetscCall((*PetscHelpPrintf)(comm, "  -%s%s: <%s>: %s (%s)\n", Prefix(prefix), opt + 1, "", text, ManSection(man)));
1163   PetscFunctionReturn(PETSC_SUCCESS);
1164 }
1165