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