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