xref: /petsc/src/sys/classes/bag/bag.c (revision 34b254c57d2aa195261fbc0db2d1455fb6d091da)
1 #include <petsc/private/petscimpl.h>
2 #include <petsc/private/bagimpl.h> /*I  "petscbag.h"   I*/
3 #include <petscviewer.h>
4 
5 /*
6       Adds item to the linked list in a bag
7 */
8 static PetscErrorCode PetscBagRegister_Private(PetscBag bag, PetscBagItem item, const char *name, const char *help)
9 {
10   PetscFunctionBegin;
11   PetscCall(PetscStrncpy(item->name, name, PETSC_BAG_NAME_LENGTH - 1));
12   PetscCall(PetscStrncpy(item->help, help, PETSC_BAG_HELP_LENGTH - 1));
13   if (bag->bagitems) {
14     PetscBagItem nitem = bag->bagitems;
15 
16     while (nitem->next) nitem = nitem->next;
17     nitem->next = item;
18   } else bag->bagitems = item;
19   bag->count++;
20   PetscFunctionReturn(PETSC_SUCCESS);
21 }
22 
23 /*@C
24   PetscBagRegisterEnum - add an enum value to a `PetscBag`
25 
26   Logically Collective
27 
28   Input Parameters:
29 + bag      - the bag of values
30 . addr     - location of enum in struct, for example `&params->dt`
31 . list     - array of strings containing names of enum values followed by enum name followed by enum prefix
32 . mdefault - the initial value, cast with (`PetscEnum`)
33 . name     - the name of the item
34 - help     - longer string with more information about the value
35 
36   Level: beginner
37 
38 .seealso: `PetscBag`, `PetscBagSetName()`, `PetscBagView()`, `PetscBagLoad()`, `PetscBagGetData()`
39           `PetscBagRegisterInt()`, `PetscBagRegisterBool()`, `PetscBagRegisterScalar()`
40           `PetscBagSetFromOptions()`, `PetscBagCreate()`, `PetscBagGetName()`
41 @*/
42 PetscErrorCode PetscBagRegisterEnum(PetscBag bag, void *addr, const char *const *list, PetscEnum mdefault, const char *name, const char *help)
43 {
44   PetscBagItem item;
45   char         nname[PETSC_BAG_NAME_LENGTH + 1];
46   PetscBool    printhelp;
47   PetscInt     i = 0;
48 
49   PetscFunctionBegin;
50   PetscAssertPointer(bag, 1);
51   PetscAssertPointer(addr, 2);
52   PetscAssertPointer(list, 3);
53   PetscAssertPointer(name, 5);
54   PetscAssertPointer(help, 6);
55   nname[0] = '-';
56   nname[1] = 0;
57   PetscCall(PetscStrlcat(nname, name, PETSC_BAG_NAME_LENGTH));
58   PetscCall(PetscOptionsHasHelp(NULL, &printhelp));
59   if (printhelp) {
60     while (list[i++]);
61     PetscCall((*PetscHelpPrintf)(bag->bagcomm, "  -%s%s <%s>: (%s) %s (choose one of) ", bag->bagprefix ? bag->bagprefix : "", name, list[mdefault], list[i - 3], help));
62     for (i = 0; list[i + 2]; i++) PetscCall((*PetscHelpPrintf)(bag->bagcomm, " %s", list[i]));
63     PetscCall((*PetscHelpPrintf)(bag->bagcomm, "\n"));
64   }
65   PetscCall(PetscOptionsGetEnum(NULL, bag->bagprefix, nname, list, &mdefault, NULL));
66 
67   PetscCall(PetscNew(&item));
68   item->dtype  = PETSC_ENUM;
69   item->offset = (PetscInt)(((size_t)addr) - ((size_t)bag));
70   PetscCheck(item->offset <= bag->bagsize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Registered item %s %s is not in bag memory space", name, help);
71   item->next  = NULL;
72   item->msize = 1;
73   PetscCall(PetscStrArrayallocpy(list, &item->list));
74   *(PetscEnum *)addr = mdefault;
75   PetscCall(PetscBagRegister_Private(bag, item, name, help));
76   PetscFunctionReturn(PETSC_SUCCESS);
77 }
78 
79 /*@C
80   PetscBagRegisterIntArray - add a `PetscInt` array to a `PetscBag`
81 
82   Logically Collective
83 
84   Input Parameters:
85 + bag   - the bag of values
86 . addr  - location of integer in struct, for example `&params->i`
87 . msize - number of entries in array
88 . name  - name of the array
89 - help  - longer string with more information about the value
90 
91   Level: beginner
92 
93 .seealso: `PetscBag`, `PetscBagSetName()`, `PetscBagView()`, `PetscBagLoad()`, `PetscBagGetData()`
94           `PetscBagRegisterInt()`, `PetscBagRegisterBool()`, `PetscBagRegisterScalar()`
95           `PetscBagSetFromOptions()`, `PetscBagCreate()`, `PetscBagGetName()`, `PetscBagRegisterEnum()`
96 @*/
97 PetscErrorCode PetscBagRegisterIntArray(PetscBag bag, void *addr, PetscInt msize, const char *name, const char *help)
98 {
99   PetscBagItem item;
100   char         nname[PETSC_BAG_NAME_LENGTH + 1];
101   PetscBool    printhelp;
102   PetscInt     i, tmp = msize;
103 
104   PetscFunctionBegin;
105   PetscAssertPointer(bag, 1);
106   PetscAssertPointer(addr, 2);
107   PetscAssertPointer(name, 4);
108   PetscAssertPointer(help, 5);
109   nname[0] = '-';
110   nname[1] = 0;
111   PetscCall(PetscStrlcat(nname, name, PETSC_BAG_NAME_LENGTH));
112   PetscCall(PetscOptionsHasHelp(NULL, &printhelp));
113   if (printhelp) {
114     PetscCall((*PetscHelpPrintf)(bag->bagcomm, "  -%s%s <", bag->bagprefix ? bag->bagprefix : "", name));
115     for (i = 0; i < msize; i++) PetscCall((*PetscHelpPrintf)(bag->bagcomm, "%" PetscInt_FMT " ", *((PetscInt *)addr) + i));
116     PetscCall((*PetscHelpPrintf)(bag->bagcomm, ">: %s \n", help));
117   }
118   PetscCall(PetscOptionsGetIntArray(NULL, bag->bagprefix, nname, (PetscInt *)addr, &tmp, NULL));
119 
120   PetscCall(PetscNew(&item));
121   item->dtype  = PETSC_INT;
122   item->offset = (PetscInt)(((size_t)addr) - ((size_t)bag));
123   PetscCheck(item->offset <= bag->bagsize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Registered item %s %s is not in bag memory space", name, help);
124   item->next  = NULL;
125   item->msize = msize;
126   PetscCall(PetscBagRegister_Private(bag, item, name, help));
127   PetscFunctionReturn(PETSC_SUCCESS);
128 }
129 
130 /*@C
131   PetscBagRegisterRealArray - add a `PetscReal` array to a `PetscBag`
132 
133   Logically Collective
134 
135   Input Parameters:
136 + bag   - the bag of values
137 . addr  - location of real array in struct, for example `&params->d`
138 . msize - number of entries in the array
139 . name  - name of the array
140 - help  - longer string with more information about the value
141 
142   Level: beginner
143 
144 .seealso: `PetscBag`, `PetscBagSetName()`, `PetscBagView()`, `PetscBagLoad()`, `PetscBagGetData()`
145           `PetscBagRegisterInt()`, `PetscBagRegisterBool()`, `PetscBagRegisterScalar()`
146           `PetscBagSetFromOptions()`, `PetscBagCreate()`, `PetscBagGetName()`, `PetscBagRegisterEnum()`
147 @*/
148 PetscErrorCode PetscBagRegisterRealArray(PetscBag bag, void *addr, PetscInt msize, const char *name, const char *help)
149 {
150   PetscBagItem item;
151   char         nname[PETSC_BAG_NAME_LENGTH + 1];
152   PetscBool    printhelp;
153   PetscInt     i, tmp = msize;
154 
155   PetscFunctionBegin;
156   PetscAssertPointer(bag, 1);
157   PetscAssertPointer(addr, 2);
158   PetscAssertPointer(name, 4);
159   PetscAssertPointer(help, 5);
160   nname[0] = '-';
161   nname[1] = 0;
162   PetscCall(PetscStrlcat(nname, name, PETSC_BAG_NAME_LENGTH));
163   PetscCall(PetscOptionsHasHelp(NULL, &printhelp));
164   if (printhelp) {
165     PetscCall((*PetscHelpPrintf)(bag->bagcomm, "  -%s%s <", bag->bagprefix ? bag->bagprefix : "", name));
166     for (i = 0; i < msize; i++) PetscCall((*PetscHelpPrintf)(bag->bagcomm, "%g ", (double)(*((PetscReal *)addr) + i)));
167     PetscCall((*PetscHelpPrintf)(bag->bagcomm, ">: %s \n", help));
168   }
169   PetscCall(PetscOptionsGetRealArray(NULL, bag->bagprefix, nname, (PetscReal *)addr, &tmp, NULL));
170 
171   PetscCall(PetscNew(&item));
172   item->dtype  = PETSC_REAL;
173   item->offset = (PetscInt)(((size_t)addr) - ((size_t)bag));
174   PetscCheck(item->offset <= bag->bagsize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Registered item %s %s is not in bag memory space", name, help);
175   item->next  = NULL;
176   item->msize = msize;
177   PetscCall(PetscBagRegister_Private(bag, item, name, help));
178   PetscFunctionReturn(PETSC_SUCCESS);
179 }
180 
181 /*@C
182   PetscBagRegisterInt - add a `PetscInt` value to a `PetscBag`
183 
184   Logically Collective
185 
186   Input Parameters:
187 + bag      - the bag of values
188 . addr     - location of integer in struct, for example `&params->i`
189 . mdefault - the initial value
190 . name     - name of the integer
191 - help     - longer string with more information about the value
192 
193   Level: beginner
194 
195 .seealso: `PetscBag`, `PetscBagSetName()`, `PetscBagView()`, `PetscBagLoad()`, `PetscBagGetData()`
196           `PetscBagRegisterInt64()`, `PetscBagRegisterBool()`, `PetscBagRegisterScalar()`
197           `PetscBagSetFromOptions()`, `PetscBagCreate()`, `PetscBagGetName()`, `PetscBagRegisterEnum()`
198 @*/
199 PetscErrorCode PetscBagRegisterInt(PetscBag bag, void *addr, PetscInt mdefault, const char *name, const char *help)
200 {
201   PetscBagItem item;
202   char         nname[PETSC_BAG_NAME_LENGTH + 1];
203   PetscBool    printhelp;
204 
205   PetscFunctionBegin;
206   PetscAssertPointer(bag, 1);
207   PetscAssertPointer(addr, 2);
208   PetscAssertPointer(name, 4);
209   PetscAssertPointer(help, 5);
210   nname[0] = '-';
211   nname[1] = 0;
212   PetscCall(PetscStrlcat(nname, name, PETSC_BAG_NAME_LENGTH));
213   PetscCall(PetscOptionsHasHelp(NULL, &printhelp));
214   if (printhelp) PetscCall((*PetscHelpPrintf)(bag->bagcomm, "  -%s%s <%" PetscInt_FMT ">: %s \n", bag->bagprefix ? bag->bagprefix : "", name, mdefault, help));
215   PetscCall(PetscOptionsGetInt(NULL, bag->bagprefix, nname, &mdefault, NULL));
216 
217   PetscCall(PetscNew(&item));
218   item->dtype  = PETSC_INT;
219   item->offset = (PetscInt)(((size_t)addr) - ((size_t)bag));
220   PetscCheck(item->offset <= bag->bagsize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Registered item %s %s is not in bag memory space", name, help);
221   item->next        = NULL;
222   item->msize       = 1;
223   *(PetscInt *)addr = mdefault;
224   PetscCall(PetscBagRegister_Private(bag, item, name, help));
225   PetscFunctionReturn(PETSC_SUCCESS);
226 }
227 
228 /*@C
229   PetscBagRegisterInt64 - add a `PetscInt64` value to a `PetscBag`
230 
231   Logically Collective
232 
233   Input Parameters:
234 + bag      - the bag of values
235 . addr     - location of integer in struct, for example `&params->i`
236 . mdefault - the initial value
237 . name     - name of the integer
238 - help     - longer string with more information about the value
239 
240   Level: beginner
241 
242 .seealso: `PetscBag`, `PetscBagSetName()`, `PetscBagView()`, `PetscBagLoad()`, `PetscBagGetData()`
243           `PetscBagRegisterInt()`, `PetscBagRegisterBool()`, `PetscBagRegisterScalar()`
244           `PetscBagSetFromOptions()`, `PetscBagCreate()`, `PetscBagGetName()`, `PetscBagRegisterEnum()`
245 @*/
246 PetscErrorCode PetscBagRegisterInt64(PetscBag bag, void *addr, PetscInt64 mdefault, const char *name, const char *help)
247 {
248   PetscBagItem item;
249   char         nname[PETSC_BAG_NAME_LENGTH + 1];
250   PetscBool    printhelp;
251   PetscInt     odefault;
252   PetscBool    flg;
253 
254   PetscFunctionBegin;
255   nname[0] = '-';
256   nname[1] = 0;
257 
258   PetscCall(PetscIntCast(mdefault, &odefault));
259   PetscCall(PetscStrlcat(nname, name, PETSC_BAG_NAME_LENGTH));
260   PetscCall(PetscOptionsHasHelp(NULL, &printhelp));
261   if (printhelp) PetscCall((*PetscHelpPrintf)(bag->bagcomm, "  -%s%s <%" PetscInt_FMT ">: %s \n", bag->bagprefix ? bag->bagprefix : "", name, odefault, help));
262   PetscCall(PetscOptionsGetInt(NULL, bag->bagprefix, nname, &odefault, &flg));
263   if (flg) mdefault = odefault;
264 
265   PetscCall(PetscNew(&item));
266   item->dtype  = PETSC_INT;
267   item->offset = (PetscInt)(((size_t)addr) - ((size_t)bag));
268   PetscCheck(item->offset <= bag->bagsize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Registered item %s %s is not in bag memory space", name, help);
269   item->next          = NULL;
270   item->msize         = 1;
271   *(PetscInt64 *)addr = mdefault;
272   PetscCall(PetscBagRegister_Private(bag, item, name, help));
273   PetscFunctionReturn(PETSC_SUCCESS);
274 }
275 
276 /*@C
277   PetscBagRegisterBoolArray - add a n `PetscBool` values to a `PetscBag`
278 
279   Logically Collective
280 
281   Input Parameters:
282 + bag   - the bag of values
283 . addr  - location of boolean array in struct, for example `&params->b`
284 . msize - number of entries in array
285 . name  - name of the boolean array
286 - help  - longer string with more information about the value
287 
288   Level: beginner
289 
290 .seealso: `PetscBag`, `PetscBagSetName()`, `PetscBagView()`, `PetscBagLoad()`, `PetscBagGetData()`
291           `PetscBagRegisterInt()`, `PetscBagRegisterBool()`, `PetscBagRegisterScalar()`
292           `PetscBagSetFromOptions()`, `PetscBagCreate()`, `PetscBagGetName()`, `PetscBagRegisterEnum()`
293 @*/
294 PetscErrorCode PetscBagRegisterBoolArray(PetscBag bag, void *addr, PetscInt msize, const char *name, const char *help)
295 {
296   PetscBagItem item;
297   char         nname[PETSC_BAG_NAME_LENGTH + 1];
298   PetscBool    printhelp;
299   PetscInt     i, tmp = msize;
300 
301   PetscFunctionBegin;
302   PetscAssertPointer(bag, 1);
303   PetscAssertPointer(addr, 2);
304   PetscAssertPointer(name, 4);
305   PetscAssertPointer(help, 5);
306   nname[0] = '-';
307   nname[1] = 0;
308   PetscCall(PetscStrlcat(nname, name, PETSC_BAG_NAME_LENGTH));
309   PetscCall(PetscOptionsHasHelp(NULL, &printhelp));
310   if (printhelp) {
311     PetscCall((*PetscHelpPrintf)(bag->bagcomm, "  -%s%s <", bag->bagprefix ? bag->bagprefix : "", name));
312     for (i = 0; i < msize; i++) PetscCall((*PetscHelpPrintf)(bag->bagcomm, "%" PetscInt_FMT " ", *((PetscInt *)addr) + i));
313     PetscCall((*PetscHelpPrintf)(bag->bagcomm, ">: %s \n", help));
314   }
315   PetscCall(PetscOptionsGetBoolArray(NULL, bag->bagprefix, nname, (PetscBool *)addr, &tmp, NULL));
316 
317   PetscCall(PetscNew(&item));
318   item->dtype  = PETSC_BOOL;
319   item->offset = (PetscInt)(((size_t)addr) - ((size_t)bag));
320   PetscCheck(item->offset <= bag->bagsize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Registered item %s %s is not in bag memory space", name, help);
321   item->next  = NULL;
322   item->msize = msize;
323   PetscCall(PetscBagRegister_Private(bag, item, name, help));
324   PetscFunctionReturn(PETSC_SUCCESS);
325 }
326 
327 /*@C
328   PetscBagRegisterString - add a string value to a `PetscBag`
329 
330   Logically Collective
331 
332   Input Parameters:
333 + bag      - the bag of values
334 . addr     - location of start of string in struct, for example `&params->mystring`
335 . msize    - length of the string space in the struct
336 . mdefault - the initial value
337 . name     - name of the string
338 - help     - longer string with more information about the value
339 
340   Level: beginner
341 
342   Note:
343   The struct must have the field char mystring[`msize`]; not char *mystring
344 
345 .seealso: `PetscBag`, `PetscBagSetName()`, `PetscBagView()`, `PetscBagLoad()`, `PetscBagGetData()`
346           `PetscBagRegisterInt()`, `PetscBagRegisterBool()`, `PetscBagRegisterScalar()`
347           `PetscBagSetFromOptions()`, `PetscBagCreate()`, `PetscBagGetName()`, `PetscBagRegisterEnum()`
348 @*/
349 PetscErrorCode PetscBagRegisterString(PetscBag bag, void *addr, PetscInt msize, const char *mdefault, const char *name, const char *help) PeNS
350 {
351   PetscBagItem item;
352   char         nname[PETSC_BAG_NAME_LENGTH + 1];
353   PetscBool    printhelp;
354 
355   PetscFunctionBegin;
356   PetscAssertPointer(bag, 1);
357   PetscAssertPointer(addr, 2);
358   PetscAssertPointer(mdefault, 4);
359   PetscAssertPointer(name, 5);
360   PetscAssertPointer(help, 6);
361   nname[0] = '-';
362   nname[1] = 0;
363   PetscCall(PetscStrlcat(nname, name, PETSC_BAG_NAME_LENGTH));
364   PetscCall(PetscOptionsHasHelp(NULL, &printhelp));
365   if (printhelp) PetscCall((*PetscHelpPrintf)(bag->bagcomm, "  -%s%s <%s>: %s \n", bag->bagprefix ? bag->bagprefix : "", name, mdefault, help));
366 
367   PetscCall(PetscNew(&item));
368   item->dtype  = PETSC_CHAR;
369   item->offset = (PetscInt)(((size_t)addr) - ((size_t)bag));
370   PetscCheck(item->offset <= bag->bagsize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Registered item %s %s is not in bag memory space", name, help);
371   item->next  = NULL;
372   item->msize = msize;
373   if (mdefault != (char *)addr) PetscCall(PetscStrncpy((char *)addr, mdefault, msize - 1));
374   PetscCall(PetscOptionsGetString(NULL, bag->bagprefix, nname, (char *)addr, msize, NULL));
375   PetscCall(PetscBagRegister_Private(bag, item, name, help));
376   PetscFunctionReturn(PETSC_SUCCESS);
377 }
378 
379 /*@C
380   PetscBagRegisterReal - add a `PetscReal` value to a `PetscBag`
381 
382   Logically Collective
383 
384   Input Parameters:
385 + bag      - the bag of values
386 . addr     - location of `PetscReal` in struct, for example `&params->r`
387 . mdefault - the initial value
388 . name     - name of the variable
389 - help     - longer string with more information about the value
390 
391   Level: beginner
392 
393 .seealso: `PetscBag`, `PetscBagSetName()`, `PetscBagView()`, `PetscBagLoad()`, `PetscBagGetData()`
394           `PetscBagRegisterInt()`, `PetscBagRegisterBool()`, `PetscBagRegisterScalar()`
395           `PetscBagSetFromOptions()`, `PetscBagCreate()`, `PetscBagGetName()`, `PetscBagRegisterEnum()`
396 @*/
397 PetscErrorCode PetscBagRegisterReal(PetscBag bag, void *addr, PetscReal mdefault, const char *name, const char *help)
398 {
399   PetscBagItem item;
400   char         nname[PETSC_BAG_NAME_LENGTH + 1];
401   PetscBool    printhelp;
402 
403   PetscFunctionBegin;
404   PetscAssertPointer(bag, 1);
405   PetscAssertPointer(addr, 2);
406   PetscAssertPointer(name, 4);
407   PetscAssertPointer(help, 5);
408   nname[0] = '-';
409   nname[1] = 0;
410   PetscCall(PetscStrlcat(nname, name, PETSC_BAG_NAME_LENGTH));
411   PetscCall(PetscOptionsHasHelp(NULL, &printhelp));
412   if (printhelp) PetscCall((*PetscHelpPrintf)(bag->bagcomm, "  -%s%s <%g>: %s \n", bag->bagprefix ? bag->bagprefix : "", name, (double)mdefault, help));
413   PetscCall(PetscOptionsGetReal(NULL, bag->bagprefix, nname, &mdefault, NULL));
414 
415   PetscCall(PetscNew(&item));
416   item->dtype  = PETSC_REAL;
417   item->offset = (PetscInt)(((size_t)addr) - ((size_t)bag));
418   PetscCheck(item->offset <= bag->bagsize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Registered item %s %s is not in bag memory space", name, help);
419   item->next         = NULL;
420   item->msize        = 1;
421   *(PetscReal *)addr = mdefault;
422   PetscCall(PetscBagRegister_Private(bag, item, name, help));
423   PetscFunctionReturn(PETSC_SUCCESS);
424 }
425 
426 /*@C
427   PetscBagRegisterScalar - add a `PetscScalar` value to a `PetscBag`
428 
429   Logically Collective
430 
431   Input Parameters:
432 + bag      - the bag of values
433 . addr     - location of `PetscScalar` in struct, for example `&params->c`
434 . mdefault - the initial value
435 . name     - name of the variable
436 - help     - longer string with more information about the value
437 
438   Level: beginner
439 
440 .seealso: `PetscBag`, `PetscBagSetName()`, `PetscBagView()`, `PetscBagLoad()`, `PetscBagGetData()`
441           `PetscBagRegisterInt()`, `PetscBagRegisterBool()`, `PetscBagSetFromOptions()`,
442           `PetscBagCreate()`, `PetscBagGetName()`, `PetscBagRegisterEnum()`
443 @*/
444 PetscErrorCode PetscBagRegisterScalar(PetscBag bag, void *addr, PetscScalar mdefault, const char *name, const char *help)
445 {
446   PetscBagItem item;
447   char         nname[PETSC_BAG_NAME_LENGTH + 1];
448   PetscBool    printhelp;
449 
450   PetscFunctionBegin;
451   PetscAssertPointer(bag, 1);
452   PetscAssertPointer(addr, 2);
453   PetscAssertPointer(name, 4);
454   PetscAssertPointer(help, 5);
455   nname[0] = '-';
456   nname[1] = 0;
457   PetscCall(PetscStrlcat(nname, name, PETSC_BAG_NAME_LENGTH));
458   PetscCall(PetscOptionsHasHelp(NULL, &printhelp));
459   if (printhelp) PetscCall((*PetscHelpPrintf)(bag->bagcomm, "  -%s%s <%g + %gi>: %s \n", bag->bagprefix ? bag->bagprefix : "", name, (double)PetscRealPart(mdefault), (double)PetscImaginaryPart(mdefault), help));
460   PetscCall(PetscOptionsGetScalar(NULL, bag->bagprefix, nname, &mdefault, NULL));
461 
462   PetscCall(PetscNew(&item));
463   item->dtype  = PETSC_SCALAR;
464   item->offset = (PetscInt)(((size_t)addr) - ((size_t)bag));
465   PetscCheck(item->offset <= bag->bagsize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Registered item %s %s is not in bag memory space", name, help);
466   item->next           = NULL;
467   item->msize          = 1;
468   *(PetscScalar *)addr = mdefault;
469   PetscCall(PetscBagRegister_Private(bag, item, name, help));
470   PetscFunctionReturn(PETSC_SUCCESS);
471 }
472 
473 /*@C
474   PetscBagRegisterBool - add a `PetscBool` to a `PetscBag`
475 
476   Logically Collective
477 
478   Input Parameters:
479 + bag      - the bag of values
480 . addr     - location of `PetscBool` in struct, for example `&params->b`
481 . mdefault - the initial value, either `PETSC_FALSE` or `PETSC_TRUE`
482 . name     - name of the variable
483 - help     - longer string with more information about the value
484 
485   Level: beginner
486 
487 .seealso: `PetscBag`, `PetscBagSetName()`, `PetscBagView()`, `PetscBagLoad()`, `PetscBagGetData()`
488           `PetscBagRegisterInt()`, `PetscBagRegisterScalar()`
489           `PetscBagSetFromOptions()`, `PetscBagCreate()`, `PetscBagGetName()`, `PetscBagRegisterEnum()`
490 @*/
491 PetscErrorCode PetscBagRegisterBool(PetscBag bag, void *addr, PetscBool mdefault, const char *name, const char *help)
492 {
493   PetscBagItem item;
494   char         nname[PETSC_BAG_NAME_LENGTH + 1];
495   PetscBool    printhelp;
496 
497   PetscFunctionBegin;
498   PetscAssertPointer(bag, 1);
499   PetscAssertPointer(addr, 2);
500   PetscAssertPointer(name, 4);
501   PetscAssertPointer(help, 5);
502   nname[0] = '-';
503   nname[1] = 0;
504   PetscCall(PetscStrlcat(nname, name, PETSC_BAG_NAME_LENGTH));
505   PetscCall(PetscOptionsHasHelp(NULL, &printhelp));
506   if (printhelp) PetscCall((*PetscHelpPrintf)(bag->bagcomm, "  -%s%s <%s>: %s \n", bag->bagprefix ? bag->bagprefix : "", name, PetscBools[mdefault], help));
507   PetscCall(PetscOptionsGetBool(NULL, bag->bagprefix, nname, &mdefault, NULL));
508 
509   PetscCall(PetscNew(&item));
510   item->dtype  = PETSC_BOOL;
511   item->offset = (PetscInt)(((size_t)addr) - ((size_t)bag));
512   PetscCheck(item->offset <= bag->bagsize, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Registered item %s %s is not in bag memory space", name, help);
513   item->next         = NULL;
514   item->msize        = 1;
515   *(PetscBool *)addr = mdefault;
516   PetscCall(PetscBagRegister_Private(bag, item, name, help));
517   PetscFunctionReturn(PETSC_SUCCESS);
518 }
519 
520 /*@
521   PetscBagDestroy - Destroys a `PetscBag`
522 
523   Collective
524 
525   Input Parameter:
526 . bag - the bag of values
527 
528   Level: beginner
529 
530 .seealso: `PetscBag`, `PetscBagSetName()`, `PetscBagView()`, `PetscBagLoad()`, `PetscBagGetData()`
531           `PetscBagRegisterReal()`, `PetscBagRegisterInt()`, `PetscBagRegisterBool()`, `PetscBagRegisterScalar()`
532           `PetscBagSetFromOptions()`, `PetscBagCreate()`, `PetscBagGetName()`, `PetscBagRegisterEnum()`
533 @*/
534 PetscErrorCode PetscBagDestroy(PetscBag *bag)
535 {
536   PetscBagItem nitem;
537 
538   PetscFunctionBegin;
539   if (!*bag) PetscFunctionReturn(PETSC_SUCCESS);
540   PetscAssertPointer(*bag, 1);
541   nitem = (*bag)->bagitems;
542   while (nitem) {
543     PetscBagItem item = nitem->next;
544 
545     if (nitem->list) PetscCall(PetscStrArrayDestroy(&nitem->list));
546     PetscCall(PetscFree(nitem));
547     nitem = item;
548   }
549   if ((*bag)->bagprefix) PetscCall(PetscFree((*bag)->bagprefix));
550   PetscCall(PetscFree(*bag));
551   PetscFunctionReturn(PETSC_SUCCESS);
552 }
553 
554 /*@
555   PetscBagSetFromOptions - Allows setting entries to a `PetscBag` using the options database
556 
557   Collective
558 
559   Input Parameter:
560 . bag - the bag of values
561 
562   Level: beginner
563 
564   Note:
565   The options database keys for the entries are of the form `-[bagprefix]_name value`
566 
567 .seealso: `PetscBag`, `PetscBagSetName()`, `PetscBagDestroy()`, `PetscBagLoad()`, `PetscBagGetData()`
568           `PetscBagRegisterReal()`, `PetscBagRegisterInt()`, `PetscBagRegisterBool()`, `PetscBagRegisterScalar()`
569           `PetscBagCreate()`, `PetscBagGetName()`, `PetscBagView()`, `PetscBagRegisterEnum()`
570 @*/
571 PetscErrorCode PetscBagSetFromOptions(PetscBag bag)
572 {
573   PetscBagItem nitem = bag->bagitems;
574   char         name[PETSC_BAG_NAME_LENGTH + 1], helpname[PETSC_BAG_NAME_LENGTH + PETSC_BAG_HELP_LENGTH + 3];
575   PetscInt     n;
576 
577   PetscFunctionBegin;
578   PetscAssertPointer(bag, 1);
579   PetscCall(PetscStrncpy(helpname, bag->bagname, sizeof(helpname)));
580   PetscCall(PetscStrlcat(helpname, " ", sizeof(helpname)));
581   PetscCall(PetscStrlcat(helpname, bag->baghelp, sizeof(helpname)));
582   PetscOptionsBegin(bag->bagcomm, bag->bagprefix, helpname, NULL);
583   while (nitem) {
584     name[0] = '-';
585     name[1] = 0;
586     PetscCall(PetscStrlcat(name, nitem->name, sizeof(name)));
587     if (nitem->dtype == PETSC_CHAR) { /* special handling for fortran required? [due to space padding vs null termination] */
588       char *value = ((char *)bag) + nitem->offset;
589       PetscCall(PetscOptionsString(name, nitem->help, "", value, value, nitem->msize, NULL));
590     } else if (nitem->dtype == PETSC_REAL) {
591       PetscReal *value = (PetscReal *)(((char *)bag) + nitem->offset);
592       if (nitem->msize == 1) {
593         PetscCall(PetscOptionsReal(name, nitem->help, "", *value, value, NULL));
594       } else {
595         n = nitem->msize;
596         PetscCall(PetscOptionsRealArray(name, nitem->help, "", value, &n, NULL));
597       }
598     } else if (nitem->dtype == PETSC_SCALAR) {
599       PetscScalar *value = (PetscScalar *)(((char *)bag) + nitem->offset);
600       PetscCall(PetscOptionsScalar(name, nitem->help, "", *value, value, NULL));
601     } else if (nitem->dtype == PETSC_INT) {
602       PetscInt *value = (PetscInt *)(((char *)bag) + nitem->offset);
603       if (nitem->msize == 1) {
604         PetscCall(PetscOptionsInt(name, nitem->help, "", *value, value, NULL));
605       } else {
606         n = nitem->msize;
607         PetscCall(PetscOptionsIntArray(name, nitem->help, "", value, &n, NULL));
608       }
609     } else if (nitem->dtype == PETSC_ENUM) {
610       PetscEnum *value = (PetscEnum *)(((char *)bag) + nitem->offset);
611       PetscInt   i     = 0;
612       while (nitem->list[i++]);
613       PetscCall(PetscOptionsEnum(name, nitem->help, nitem->list[i - 3], (const char *const *)nitem->list, *value, value, NULL));
614     } else if (nitem->dtype == PETSC_BOOL) {
615       PetscBool *value = (PetscBool *)(((char *)bag) + nitem->offset);
616       if (nitem->msize == 1) {
617         PetscCall(PetscOptionsBool(name, nitem->help, "", *value, value, NULL));
618       } else {
619         n = nitem->msize;
620         PetscCall(PetscOptionsBoolArray(name, nitem->help, "", value, &n, NULL));
621       }
622     }
623     nitem = nitem->next;
624   }
625   PetscOptionsEnd();
626   PetscFunctionReturn(PETSC_SUCCESS);
627 }
628 
629 /*@
630   PetscBagView - Views a bag of values as either ASCII text or a binary file
631 
632   Collective
633 
634   Input Parameters:
635 + bag  - the bag of values
636 - view - location to view the values
637 
638   Level: beginner
639 
640   Note:
641   Currently PETSc bags saved in a binary file can only be read back
642   in on a machine with the same binary format.
643 
644 .seealso: `PetscBag`, `PetscBagSetName()`, `PetscBagDestroy()`, `PetscBagLoad()`, `PetscBagGetData()`
645           `PetscBagRegisterReal()`, `PetscBagRegisterInt()`, `PetscBagRegisterBool()`, `PetscBagRegisterScalar()`, `PetscBagRegisterEnum()`
646           `PetscBagSetFromOptions()`, `PetscBagCreate()`, `PetscBagGetName()`
647 @*/
648 PetscErrorCode PetscBagView(PetscBag bag, PetscViewer view)
649 {
650   PetscBool    isascii, isbinary;
651   PetscBagItem nitem = bag->bagitems;
652 
653   PetscFunctionBegin;
654   PetscAssertPointer(bag, 1);
655   PetscValidHeaderSpecific(view, PETSC_VIEWER_CLASSID, 2);
656   PetscCall(PetscObjectTypeCompare((PetscObject)view, PETSCVIEWERASCII, &isascii));
657   PetscCall(PetscObjectTypeCompare((PetscObject)view, PETSCVIEWERBINARY, &isbinary));
658   if (isascii) {
659     if (bag->bagprefix) {
660       PetscCall(PetscViewerASCIIPrintf(view, "PetscBag Object:  %s (%s) %s\n", bag->bagname, bag->bagprefix, bag->baghelp));
661     } else {
662       PetscCall(PetscViewerASCIIPrintf(view, "PetscBag Object:  %s %s\n", bag->bagname, bag->baghelp));
663     }
664     while (nitem) {
665       if (nitem->dtype == PETSC_CHAR) {
666         char *value             = ((char *)bag) + nitem->offset;
667         char  tmp               = value[nitem->msize - 1]; /* special handling for fortran chars without null terminator */
668         value[nitem->msize - 1] = 0;
669         PetscCall(PetscViewerASCIIPrintf(view, "  %s = %s; %s\n", nitem->name, value, nitem->help));
670         value[nitem->msize - 1] = tmp;
671       } else if (nitem->dtype == PETSC_REAL) {
672         PetscReal *value = (PetscReal *)(((char *)bag) + nitem->offset);
673         PetscInt   i;
674         PetscCall(PetscViewerASCIIPrintf(view, "  %s = ", nitem->name));
675         for (i = 0; i < nitem->msize; i++) PetscCall(PetscViewerASCIIPrintf(view, "%g ", (double)value[i]));
676         PetscCall(PetscViewerASCIIPrintf(view, "; %s\n", nitem->help));
677       } else if (nitem->dtype == PETSC_SCALAR) {
678         PetscScalar value = *(PetscScalar *)(((char *)bag) + nitem->offset);
679 #if defined(PETSC_USE_COMPLEX)
680         if ((double)PetscImaginaryPart(value)) {
681           PetscCall(PetscViewerASCIIPrintf(view, "  %s = %g + %gi; %s\n", nitem->name, (double)PetscRealPart(value), (double)PetscImaginaryPart(value), nitem->help));
682         } else {
683           PetscCall(PetscViewerASCIIPrintf(view, "  %s = %g; %s\n", nitem->name, (double)PetscRealPart(value), nitem->help));
684         }
685 #else
686         PetscCall(PetscViewerASCIIPrintf(view, "  %s = %g; %s\n", nitem->name, (double)value, nitem->help));
687 #endif
688       } else if (nitem->dtype == PETSC_INT) {
689         PetscInt i, *value = (PetscInt *)(((char *)bag) + nitem->offset);
690         PetscCall(PetscViewerASCIIPrintf(view, "  %s = ", nitem->name));
691         for (i = 0; i < nitem->msize; i++) PetscCall(PetscViewerASCIIPrintf(view, "%" PetscInt_FMT " ", value[i]));
692         PetscCall(PetscViewerASCIIPrintf(view, "; %s\n", nitem->help));
693       } else if (nitem->dtype == PETSC_BOOL) {
694         PetscBool *value = (PetscBool *)(((char *)bag) + nitem->offset);
695         PetscInt   i;
696         /* some Fortran compilers use -1 as boolean */
697         PetscCall(PetscViewerASCIIPrintf(view, "  %s = ", nitem->name));
698         for (i = 0; i < nitem->msize; i++) {
699           if (((int)value[i]) == -1) value[i] = PETSC_TRUE;
700           /* the checks here with != PETSC_FALSE and PETSC_TRUE is a special case; here we truly demand that the value be 0 or 1 */
701           PetscCheck(value[i] == PETSC_FALSE || value[i] == PETSC_TRUE, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Boolean value for %s %s is corrupt; integer value %" PetscInt_FMT, nitem->name, nitem->help, (PetscInt)value[i]);
702           PetscCall(PetscViewerASCIIPrintf(view, " %s", PetscBools[value[i]]));
703         }
704         PetscCall(PetscViewerASCIIPrintf(view, "; %s\n", nitem->help));
705       } else if (nitem->dtype == PETSC_ENUM) {
706         PetscEnum value = *(PetscEnum *)(((char *)bag) + nitem->offset);
707         PetscInt  i     = 0;
708         while (nitem->list[i++]);
709         PetscCall(PetscViewerASCIIPrintf(view, "  %s = %s; (%s) %s\n", nitem->name, nitem->list[value], nitem->list[i - 3], nitem->help));
710       }
711       nitem = nitem->next;
712     }
713   } else if (isbinary) {
714     PetscInt          classid           = PETSC_BAG_FILE_CLASSID, dtype;
715     PetscInt          deprecatedbagsize = 0;
716     PetscViewerFormat format;
717     PetscCall(PetscViewerBinaryWrite(view, &classid, 1, PETSC_INT));
718     PetscCall(PetscViewerBinaryWrite(view, &deprecatedbagsize, 1, PETSC_INT));
719     PetscCall(PetscViewerBinaryWrite(view, &bag->count, 1, PETSC_INT));
720     PetscCall(PetscViewerBinaryWrite(view, bag->bagname, PETSC_BAG_NAME_LENGTH, PETSC_CHAR));
721     PetscCall(PetscViewerBinaryWrite(view, bag->baghelp, PETSC_BAG_HELP_LENGTH, PETSC_CHAR));
722     while (nitem) {
723       PetscCall(PetscViewerBinaryWrite(view, &nitem->offset, 1, PETSC_INT));
724       dtype = (PetscInt)nitem->dtype;
725       PetscCall(PetscViewerBinaryWrite(view, &dtype, 1, PETSC_INT));
726       PetscCall(PetscViewerBinaryWrite(view, nitem->name, PETSC_BAG_NAME_LENGTH, PETSC_CHAR));
727       PetscCall(PetscViewerBinaryWrite(view, nitem->help, PETSC_BAG_HELP_LENGTH, PETSC_CHAR));
728       PetscCall(PetscViewerBinaryWrite(view, &nitem->msize, 1, PETSC_INT));
729       /* some Fortran compilers use -1 as boolean */
730       if (dtype == PETSC_BOOL && (*(int *)(((char *)bag) + nitem->offset) == -1)) *(int *)(((char *)bag) + nitem->offset) = PETSC_TRUE;
731 
732       PetscCall(PetscViewerBinaryWrite(view, (char *)bag + nitem->offset, nitem->msize, nitem->dtype));
733       if (dtype == PETSC_ENUM) PetscCall(PetscViewerBinaryWriteStringArray(view, (const char *const *)nitem->list));
734       nitem = nitem->next;
735     }
736     PetscCall(PetscViewerGetFormat(view, &format));
737     if (format == PETSC_VIEWER_BINARY_MATLAB) {
738       MPI_Comm comm;
739       FILE    *info;
740       PetscCall(PetscObjectGetComm((PetscObject)view, &comm));
741       PetscCall(PetscViewerBinaryGetInfoPointer(view, &info));
742       PetscCall(PetscFPrintf(comm, info, "#--- begin code written by PetscViewerBinary for MATLAB format ---#\n"));
743       PetscCall(PetscFPrintf(comm, info, "#$$ Set.%s = PetscBinaryRead(fd);\n", bag->bagname));
744       PetscCall(PetscFPrintf(comm, info, "#--- end code written by PetscViewerBinary for MATLAB format ---#\n\n"));
745     }
746   }
747   PetscFunctionReturn(PETSC_SUCCESS);
748 }
749 
750 /*@
751   PetscBagViewFromOptions - Processes command line options to determine if/how a `PetscBag` is to be viewed.
752 
753   Collective
754 
755   Input Parameters:
756 + bag        - the object
757 . bobj       - optional other object that provides prefix (if `NULL` then the prefix in obj is used)
758 - optionname - option to activate viewing
759 
760   Level: intermediate
761 
762 .seealso: `PetscBagCreate()`, `PetscBag`, `PetscViewer`
763 @*/
764 PetscErrorCode PetscBagViewFromOptions(PetscBag bag, PetscObject bobj, const char optionname[])
765 {
766   static PetscBool  incall = PETSC_FALSE;
767   PetscViewer       viewer;
768   PetscViewerFormat format;
769   const char       *prefix, *bprefix = NULL;
770   PetscBool         flg;
771 
772   PetscFunctionBegin;
773   if (incall) PetscFunctionReturn(PETSC_SUCCESS);
774   incall = PETSC_TRUE;
775   PetscAssertPointer(bag, 1);
776   if (bobj) PetscCall(PetscObjectGetOptionsPrefix(bobj, &bprefix));
777   prefix = bobj ? bprefix : bag->bagprefix;
778   PetscCall(PetscOptionsCreateViewer(bag->bagcomm, NULL, prefix, optionname, &viewer, &format, &flg));
779   if (flg) {
780     PetscCall(PetscViewerPushFormat(viewer, format));
781     PetscCall(PetscBagView(bag, viewer));
782     PetscCall(PetscViewerFlush(viewer));
783     PetscCall(PetscViewerPopFormat(viewer));
784     PetscCall(PetscViewerDestroy(&viewer));
785   }
786   incall = PETSC_FALSE;
787   PetscFunctionReturn(PETSC_SUCCESS);
788 }
789 
790 /*@
791   PetscBagLoad - Loads a bag of values from a binary file
792 
793   Collective
794 
795   Input Parameters:
796 + view - file to load values from
797 - bag  - the bag of values
798 
799   Level: beginner
800 
801   Note:
802   You must have created and registered all the fields in the bag before loading into it. This only loads values.
803 
804 .seealso: `PetscBag`, `PetscBagSetName()`, `PetscBagDestroy()`, `PetscBagView()`, `PetscBagGetData()`
805           `PetscBagRegisterReal()`, `PetscBagRegisterInt()`, `PetscBagRegisterBool()`, `PetscBagRegisterScalar()`
806           `PetscBagSetFromOptions()`, `PetscBagCreate()`, `PetscBagGetName()`, `PetscBagRegisterEnum()`
807 @*/
808 PetscErrorCode PetscBagLoad(PetscViewer view, PetscBag bag)
809 {
810   PetscBool    isbinary;
811   PetscInt     classid, bagcount, dtype, msize, offset, deprecatedbagsize;
812   char         name[PETSC_BAG_NAME_LENGTH], help[PETSC_BAG_HELP_LENGTH], **list;
813   PetscBagItem nitem;
814   MPI_Comm     comm;
815   PetscMPIInt  flag;
816 
817   PetscFunctionBegin;
818   PetscValidHeaderSpecific(view, PETSC_VIEWER_CLASSID, 1);
819   PetscAssertPointer(bag, 2);
820   PetscCall(PetscObjectGetComm((PetscObject)view, &comm));
821   PetscCallMPI(MPI_Comm_compare(comm, bag->bagcomm, &flag));
822   PetscCheck(flag == MPI_CONGRUENT || flag == MPI_IDENT, PETSC_COMM_SELF, PETSC_ERR_ARG_NOTSAMECOMM, "Different communicators in the viewer and bag");
823   PetscCall(PetscObjectTypeCompare((PetscObject)view, PETSCVIEWERBINARY, &isbinary));
824   PetscCheck(isbinary, PETSC_COMM_SELF, PETSC_ERR_SUP, "No support for this viewer type");
825 
826   PetscCall(PetscViewerBinaryRead(view, &classid, 1, NULL, PETSC_INT));
827   PetscCheck(classid == PETSC_BAG_FILE_CLASSID, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Not PetscBag next in binary file");
828   PetscCall(PetscViewerBinaryRead(view, &deprecatedbagsize, 1, NULL, PETSC_INT));
829   PetscCall(PetscViewerBinaryRead(view, &bagcount, 1, NULL, PETSC_INT));
830   PetscCheck(bagcount == bag->count, comm, PETSC_ERR_ARG_INCOMP, "Bag in file has different number of entries %" PetscInt_FMT " then passed in bag %" PetscInt_FMT, bagcount, bag->count);
831   PetscCall(PetscViewerBinaryRead(view, bag->bagname, PETSC_BAG_NAME_LENGTH, NULL, PETSC_CHAR));
832   PetscCall(PetscViewerBinaryRead(view, bag->baghelp, PETSC_BAG_HELP_LENGTH, NULL, PETSC_CHAR));
833 
834   nitem = bag->bagitems;
835   for (PetscInt i = 0; i < bagcount; i++) {
836     PetscCall(PetscViewerBinaryRead(view, &offset, 1, NULL, PETSC_INT));
837     /* ignore the offset in the file */
838     PetscCall(PetscViewerBinaryRead(view, &dtype, 1, NULL, PETSC_INT));
839     PetscCall(PetscViewerBinaryRead(view, name, PETSC_BAG_NAME_LENGTH, NULL, PETSC_CHAR));
840     PetscCall(PetscViewerBinaryRead(view, help, PETSC_BAG_HELP_LENGTH, NULL, PETSC_CHAR));
841     PetscCall(PetscViewerBinaryRead(view, &msize, 1, NULL, PETSC_INT));
842 
843     if (dtype == (PetscInt)PETSC_CHAR) {
844       PetscCall(PetscViewerBinaryRead(view, ((char *)bag) + nitem->offset, msize, NULL, PETSC_CHAR));
845     } else if (dtype == (PetscInt)PETSC_REAL) {
846       PetscCall(PetscViewerBinaryRead(view, ((char *)bag) + nitem->offset, msize, NULL, PETSC_REAL));
847     } else if (dtype == (PetscInt)PETSC_SCALAR) {
848       PetscCall(PetscViewerBinaryRead(view, ((char *)bag) + nitem->offset, 1, NULL, PETSC_SCALAR));
849     } else if (dtype == (PetscInt)PETSC_INT) {
850       PetscCall(PetscViewerBinaryRead(view, ((char *)bag) + nitem->offset, msize, NULL, PETSC_INT));
851     } else if (dtype == (PetscInt)PETSC_BOOL) {
852       PetscCall(PetscViewerBinaryRead(view, ((char *)bag) + nitem->offset, msize, NULL, PETSC_BOOL));
853     } else if (dtype == (PetscInt)PETSC_ENUM) {
854       PetscCall(PetscViewerBinaryRead(view, ((char *)bag) + nitem->offset, 1, NULL, PETSC_ENUM));
855       PetscCall(PetscViewerBinaryReadStringArray(view, &list));
856       /* don't need to save list because it is already registered in the bag */
857       PetscCall(PetscFree(list));
858     }
859     nitem = nitem->next;
860   }
861   PetscFunctionReturn(PETSC_SUCCESS);
862 }
863 
864 /*@C
865   PetscBagCreate - Create a bag of values. A `PetscBag` is a representation of a C struct that can be saved to and read from files,
866   can have values set from the options database
867 
868   Collective
869 
870   Input Parameters:
871 + comm    - communicator to share bag
872 - bagsize - size of the C structure holding the values, for example `sizeof(mystruct)`
873 
874   Output Parameter:
875 . bag - the bag of values
876 
877   Level: intermediate
878 
879   Notes:
880   After creating the bag, for each entry in the C struct call the appropriate `PetscBagRegisterInt()` etc to define the C structs layout
881 
882   The size of the struct must be small enough to fit in a `PetscInt`; by default
883   `PetscInt` is 4 bytes; this means a bag cannot be larger than 2 gigabytes in length.
884   The warning about casting to a shorter length can be ignored below unless your struct is too large
885 
886 .seealso: `PetscBag`, `PetscBagGetName()`, `PetscBagView()`, `PetscBagLoad()`, `PetscBagGetData()`
887           `PetscBagRegisterReal()`, `PetscBagRegisterInt()`, `PetscBagRegisterBool()`, `PetscBagRegisterScalar()`
888           `PetscBagSetFromOptions()`, `PetscBagDestroy()`, `PetscBagRegisterEnum()`
889 @*/
890 PetscErrorCode PetscBagCreate(MPI_Comm comm, size_t bagsize, PetscBag *bag)
891 {
892   const size_t totalsize = bagsize + sizeof(struct _n_PetscBag) + sizeof(PetscScalar);
893 
894   PetscFunctionBegin;
895   PetscAssertPointer(bag, 3);
896 
897   PetscCall(PetscInfo(NULL, "Creating Bag with total size %d\n", (int)totalsize));
898   PetscCall(PetscCalloc(totalsize, bag));
899   PetscCall(PetscIntCast(totalsize, &(*bag)->bagsize));
900   (*bag)->bagcomm        = comm;
901   (*bag)->bagprefix      = NULL;
902   (*bag)->structlocation = (void *)(((char *)(*bag)) + sizeof(PetscScalar) * (sizeof(struct _n_PetscBag) / sizeof(PetscScalar)) + sizeof(PetscScalar));
903   PetscFunctionReturn(PETSC_SUCCESS);
904 }
905 
906 /*@
907   PetscBagSetName - Sets the name of a bag of values
908 
909   Not Collective
910 
911   Level: intermediate
912 
913   Input Parameters:
914 + bag  - the bag of values
915 . name - the name assigned to the bag
916 - help - help message for bag
917 
918 .seealso: `PetscBag`, `PetscBagGetName()`, `PetscBagView()`, `PetscBagLoad()`, `PetscBagGetData()`
919           `PetscBagRegisterReal()`, `PetscBagRegisterInt()`, `PetscBagRegisterBool()`, `PetscBagRegisterScalar()`
920           `PetscBagSetFromOptions()`, `PetscBagCreate()`, `PetscBagDestroy()`, `PetscBagRegisterEnum()`
921 @*/
922 PetscErrorCode PetscBagSetName(PetscBag bag, const char name[], const char help[])
923 {
924   PetscFunctionBegin;
925   PetscAssertPointer(bag, 1);
926   PetscAssertPointer(name, 2);
927   PetscAssertPointer(help, 3);
928   PetscCall(PetscStrncpy(bag->bagname, name, PETSC_BAG_NAME_LENGTH - 1));
929   PetscCall(PetscStrncpy(bag->baghelp, help, PETSC_BAG_HELP_LENGTH - 1));
930   PetscFunctionReturn(PETSC_SUCCESS);
931 }
932 
933 /*@C
934   PetscBagGetName - Gets the name of a bag of values
935 
936   Not Collective
937 
938   Level: intermediate
939 
940   Input Parameter:
941 . bag - the bag of values
942 
943   Output Parameter:
944 . name - the name assigned to the bag
945 
946 .seealso: `PetscBag`, `PetscBagSetName()`, `PetscBagView()`, `PetscBagLoad()`, `PetscBagGetData()`
947           `PetscBagRegisterReal()`, `PetscBagRegisterInt()`, `PetscBagRegisterBool()`, `PetscBagRegisterScalar()`
948           `PetscBagSetFromOptions()`, `PetscBagCreate()`, `PetscBagDestroy()`, `PetscBagRegisterEnum()`
949 @*/
950 PetscErrorCode PetscBagGetName(PetscBag bag, const char **name)
951 {
952   PetscFunctionBegin;
953   PetscAssertPointer(bag, 1);
954   PetscAssertPointer(name, 2);
955   *name = bag->bagname;
956   PetscFunctionReturn(PETSC_SUCCESS);
957 }
958 
959 /*@C
960   PetscBagGetData - Gives back the user - access to memory that
961   can be used for storing user-data-structure
962 
963   Not Collective
964 
965   Input Parameter:
966 . bag - the bag of values
967 
968   Output Parameter:
969 . data - pointer to memory that will have user-data-structure, this can be cast to a pointer of the type the C struct used in
970          defining the bag
971 
972   Level: intermediate
973 
974 .seealso: `PetscBag`, `PetscBagSetName()`, `PetscBagView()`, `PetscBagLoad()`
975           `PetscBagRegisterReal()`, `PetscBagRegisterInt()`, `PetscBagRegisterBool()`, `PetscBagRegisterScalar()`
976           `PetscBagSetFromOptions()`, `PetscBagCreate()`, `PetscBagDestroy()`, `PetscBagRegisterEnum()`
977 @*/
978 PetscErrorCode PetscBagGetData(PetscBag bag, PeCtx data)
979 {
980   PetscFunctionBegin;
981   PetscAssertPointer(bag, 1);
982   PetscAssertPointer(data, 2);
983   *(void **)data = bag->structlocation;
984   PetscFunctionReturn(PETSC_SUCCESS);
985 }
986 
987 /*@
988   PetscBagSetOptionsPrefix - Sets the prefix used for searching for all
989   `PetscBag` items in the options database.
990 
991   Logically Collective
992 
993   Level: intermediate
994 
995   Input Parameters:
996 + bag - the bag of values
997 - pre - the prefix to prepend all Bag item names with.
998 
999   Note:
1000   Must be called prior to registering any of the bag items.
1001 
1002 .seealso: `PetscBag`, `PetscBagRegisterReal()`, `PetscBagRegisterInt()`, `PetscBagRegisterBool()`, `PetscBagRegisterScalar()`
1003           `PetscBagSetFromOptions()`, `PetscBagCreate()`, `PetscBagDestroy()`, `PetscBagRegisterEnum()`
1004 @*/
1005 PetscErrorCode PetscBagSetOptionsPrefix(PetscBag bag, const char pre[])
1006 {
1007   PetscFunctionBegin;
1008   PetscAssertPointer(bag, 1);
1009   if (pre) {
1010     PetscAssertPointer(pre, 2);
1011     PetscCheck(pre[0] != '-', PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Options prefix should not begin with a hyphen");
1012     PetscCall(PetscFree(bag->bagprefix));
1013     PetscCall(PetscStrallocpy(pre, &bag->bagprefix));
1014   } else PetscCall(PetscFree(bag->bagprefix));
1015   PetscFunctionReturn(PETSC_SUCCESS);
1016 }
1017 
1018 /*@C
1019   PetscBagGetNames - Get the names of all entries in the bag
1020 
1021   Not Collective
1022 
1023   Input Parameter:
1024 . bag - the bag of values
1025 
1026   Output Parameter:
1027 . names - pass in an array of char pointers to hold the names. The array must be as long as the number of items in the bag.
1028 
1029   Level: intermediate
1030 
1031 .seealso: `PetscBag`, `PetscBagGetName()`, `PetscBagSetName()`, `PetscBagCreate()`, `PetscBagGetData()`
1032           `PetscBagRegisterReal()`, `PetscBagRegisterInt()`, `PetscBagRegisterBool()`, `PetscBagRegisterScalar()`, `PetscBagRegisterEnum()`
1033 @*/
1034 PetscErrorCode PetscBagGetNames(PetscBag bag, const char *names[])
1035 {
1036   PetscBagItem nitem = bag->bagitems;
1037 
1038   PetscFunctionBegin;
1039   PetscAssertPointer(bag, 1);
1040   PetscAssertPointer(names, 2);
1041   for (PetscInt n = 0; nitem; ++n, nitem = nitem->next) names[n] = nitem->name;
1042   PetscFunctionReturn(PETSC_SUCCESS);
1043 }
1044