Actual source code: reg.c
2: /*
3: Provides a general mechanism to allow one to register new routines in
4: dynamic libraries for many of the PETSc objects (including, e.g., KSP and PC).
5: */
6: #include <petsc/private/petscimpl.h>
7: #include <petscviewer.h>
9: #include <petsc/private/hashmap.h>
10: /*
11: This is the default list used by PETSc with the PetscDLLibrary register routines
12: */
13: PetscDLLibrary PetscDLLibrariesLoaded = NULL;
15: #if defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES)
17: static PetscErrorCode PetscLoadDynamicLibrary(const char *name, PetscBool *found)
18: {
19: char libs[PETSC_MAX_PATH_LEN], dlib[PETSC_MAX_PATH_LEN];
21: PetscFunctionBegin;
22: PetscCall(PetscStrncpy(libs, "${PETSC_LIB_DIR}/libpetsc", sizeof(libs)));
23: PetscCall(PetscStrlcat(libs, name, sizeof(libs)));
24: PetscCall(PetscDLLibraryRetrieve(PETSC_COMM_WORLD, libs, dlib, 1024, found));
25: if (*found) {
26: PetscCall(PetscDLLibraryAppend(PETSC_COMM_WORLD, &PetscDLLibrariesLoaded, dlib));
27: } else {
28: PetscCall(PetscStrncpy(libs, "${PETSC_DIR}/${PETSC_ARCH}/lib/libpetsc", sizeof(libs)));
29: PetscCall(PetscStrlcat(libs, name, sizeof(libs)));
30: PetscCall(PetscDLLibraryRetrieve(PETSC_COMM_WORLD, libs, dlib, 1024, found));
31: if (*found) PetscCall(PetscDLLibraryAppend(PETSC_COMM_WORLD, &PetscDLLibrariesLoaded, dlib));
32: }
33: PetscFunctionReturn(PETSC_SUCCESS);
34: }
35: #endif
37: #if defined(PETSC_USE_SINGLE_LIBRARY) && !(defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES))
38: PETSC_EXTERN PetscErrorCode AOInitializePackage(void);
39: PETSC_EXTERN PetscErrorCode PetscSFInitializePackage(void);
40: #if !defined(PETSC_USE_COMPLEX)
41: PETSC_EXTERN PetscErrorCode CharacteristicInitializePackage(void);
42: #endif
43: PETSC_EXTERN PetscErrorCode ISInitializePackage(void);
44: PETSC_EXTERN PetscErrorCode VecInitializePackage(void);
45: PETSC_EXTERN PetscErrorCode MatInitializePackage(void);
46: PETSC_EXTERN PetscErrorCode DMInitializePackage(void);
47: PETSC_EXTERN PetscErrorCode PCInitializePackage(void);
48: PETSC_EXTERN PetscErrorCode KSPInitializePackage(void);
49: PETSC_EXTERN PetscErrorCode SNESInitializePackage(void);
50: PETSC_EXTERN PetscErrorCode TSInitializePackage(void);
51: PETSC_EXTERN PetscErrorCode TaoInitializePackage(void);
52: #endif
54: /*
55: PetscInitialize_DynamicLibraries - Adds the default dynamic link libraries to the
56: search path.
57: */
58: PETSC_INTERN PetscErrorCode PetscInitialize_DynamicLibraries(void)
59: {
60: char *libname[32];
61: PetscInt nmax, i;
62: PetscBool preload = PETSC_FALSE;
63: #if defined(PETSC_HAVE_ELEMENTAL)
64: PetscBool PetscInitialized = PetscInitializeCalled;
65: #endif
67: PetscFunctionBegin;
68: #if defined(PETSC_HAVE_THREADSAFETY)
69: /* These must be all initialized here because it is not safe for individual threads to call these initialize routines */
70: preload = PETSC_TRUE;
71: #endif
73: nmax = 32;
74: PetscCall(PetscOptionsGetStringArray(NULL, NULL, "-dll_prepend", libname, &nmax, NULL));
75: for (i = 0; i < nmax; i++) {
76: PetscCall(PetscDLLibraryPrepend(PETSC_COMM_WORLD, &PetscDLLibrariesLoaded, libname[i]));
77: PetscCall(PetscFree(libname[i]));
78: }
80: PetscCall(PetscOptionsGetBool(NULL, NULL, "-library_preload", &preload, NULL));
81: if (!preload) {
82: PetscCall(PetscSysInitializePackage());
83: } else {
84: #if defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES)
85: PetscBool found;
86: #if defined(PETSC_USE_SINGLE_LIBRARY)
87: PetscCall(PetscLoadDynamicLibrary("", &found));
88: PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc dynamic library \n You cannot move the dynamic libraries!");
89: #else
90: PetscCall(PetscLoadDynamicLibrary("sys", &found));
91: PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc dynamic library \n You cannot move the dynamic libraries!");
92: PetscCall(PetscLoadDynamicLibrary("vec", &found));
93: PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc Vec dynamic library \n You cannot move the dynamic libraries!");
94: PetscCall(PetscLoadDynamicLibrary("mat", &found));
95: PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc Mat dynamic library \n You cannot move the dynamic libraries!");
96: PetscCall(PetscLoadDynamicLibrary("dm", &found));
97: PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc DM dynamic library \n You cannot move the dynamic libraries!");
98: PetscCall(PetscLoadDynamicLibrary("ksp", &found));
99: PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc KSP dynamic library \n You cannot move the dynamic libraries!");
100: PetscCall(PetscLoadDynamicLibrary("snes", &found));
101: PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc SNES dynamic library \n You cannot move the dynamic libraries!");
102: PetscCall(PetscLoadDynamicLibrary("ts", &found));
103: PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc TS dynamic library \n You cannot move the dynamic libraries!");
104: PetscCall(PetscLoadDynamicLibrary("tao", &found));
105: PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate Tao dynamic library \n You cannot move the dynamic libraries!");
106: #endif
107: #else /* defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES) */
108: #if defined(PETSC_USE_SINGLE_LIBRARY)
109: PetscCall(AOInitializePackage());
110: PetscCall(PetscSFInitializePackage());
111: #if !defined(PETSC_USE_COMPLEX)
112: PetscCall(CharacteristicInitializePackage());
113: #endif
114: PetscCall(ISInitializePackage());
115: PetscCall(VecInitializePackage());
116: PetscCall(MatInitializePackage());
117: PetscCall(DMInitializePackage());
118: PetscCall(PCInitializePackage());
119: PetscCall(KSPInitializePackage());
120: PetscCall(SNESInitializePackage());
121: PetscCall(TSInitializePackage());
122: PetscCall(TaoInitializePackage());
123: #else
124: SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "Cannot use -library_preload with multiple static PETSc libraries");
125: #endif
126: #endif /* defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES) */
127: }
129: #if defined(PETSC_HAVE_DYNAMIC_LIBRARIES) && defined(PETSC_USE_SHARED_LIBRARIES) && defined(PETSC_HAVE_BAMG)
130: {
131: PetscBool found;
132: PetscCall(PetscLoadDynamicLibrary("bamg", &found));
133: PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Unable to locate PETSc BAMG dynamic library \n You cannot move the dynamic libraries!");
134: }
135: #endif
137: nmax = 32;
138: PetscCall(PetscOptionsGetStringArray(NULL, NULL, "-dll_append", libname, &nmax, NULL));
139: for (i = 0; i < nmax; i++) {
140: PetscCall(PetscDLLibraryAppend(PETSC_COMM_WORLD, &PetscDLLibrariesLoaded, libname[i]));
141: PetscCall(PetscFree(libname[i]));
142: }
144: #if defined(PETSC_HAVE_ELEMENTAL)
145: /* in Fortran, PetscInitializeCalled is set to PETSC_TRUE before PetscInitialize_DynamicLibraries() */
146: /* in C, it is not the case, but the value is forced to PETSC_TRUE so that PetscRegisterFinalize() is called */
147: PetscInitializeCalled = PETSC_TRUE;
148: PetscCall(PetscElementalInitializePackage());
149: PetscInitializeCalled = PetscInitialized;
150: #endif
151: PetscFunctionReturn(PETSC_SUCCESS);
152: }
154: /*
155: PetscFinalize_DynamicLibraries - Closes the opened dynamic libraries.
156: */
157: PETSC_INTERN PetscErrorCode PetscFinalize_DynamicLibraries(void)
158: {
159: PetscBool flg = PETSC_FALSE;
161: PetscFunctionBegin;
162: PetscCall(PetscOptionsGetBool(NULL, NULL, "-dll_view", &flg, NULL));
163: if (flg) PetscCall(PetscDLLibraryPrintPath(PetscDLLibrariesLoaded));
164: PetscCall(PetscDLLibraryClose(PetscDLLibrariesLoaded));
165: PetscDLLibrariesLoaded = NULL;
166: PetscFunctionReturn(PETSC_SUCCESS);
167: }
169: PETSC_HASH_MAP(HMapFunc, const char *, PetscVoidFunction, kh_str_hash_func, kh_str_hash_equal, NULL)
171: struct _n_PetscFunctionList {
172: PetscHMapFunc map;
173: };
175: /* Keep a linked list of PetscFunctionLists so that we can destroy all the left-over ones. */
176: typedef struct n_PetscFunctionListDLAll *PetscFunctionListDLAll;
177: struct n_PetscFunctionListDLAll {
178: PetscFunctionList data;
179: PetscFunctionListDLAll next;
180: };
182: static PetscFunctionListDLAll dlallhead = NULL;
184: static PetscErrorCode PetscFunctionListDLAllPush_Private(PetscFunctionList fl)
185: {
186: PetscFunctionBegin;
187: if (PetscDefined(USE_DEBUG) && !PetscDefined(HAVE_THREADSAFETY)) {
188: PetscFunctionListDLAll head;
190: PetscCall(PetscNew(&head));
191: head->data = fl;
192: head->next = dlallhead;
193: dlallhead = head;
194: }
195: PetscFunctionReturn(PETSC_SUCCESS);
196: }
198: static PetscErrorCode PetscFunctionListDLAllPop_Private(PetscFunctionList fl)
199: {
200: PetscFunctionBegin;
201: if (PetscDefined(USE_DEBUG) && !PetscDefined(HAVE_THREADSAFETY)) {
202: PetscFunctionListDLAll current = dlallhead, prev = NULL;
204: /* Remove this entry from the main DL list (if it is in it) */
205: while (current) {
206: const PetscFunctionListDLAll next = current->next;
208: if (current->data == fl) {
209: if (prev) {
210: // somewhere in the middle (or end) of the list
211: prev->next = next;
212: } else {
213: // prev = NULL implies current = dlallhead, so front of list
214: dlallhead = next;
215: }
216: PetscCall(PetscFree(current));
217: break;
218: }
219: prev = current;
220: current = next;
221: }
222: }
223: PetscFunctionReturn(PETSC_SUCCESS);
224: }
226: static PetscErrorCode PetscHMapFuncInsert_Private(PetscHMapFunc map, const char name[], PetscVoidFunction fnc)
227: {
228: PetscHashIter it;
229: PetscBool found;
231: PetscFunctionBegin;
234: PetscCall(PetscHMapFuncFind(map, name, &it, &found));
235: if (fnc) {
236: if (found) {
237: PetscCall(PetscHMapFuncIterSet(map, it, fnc));
238: } else {
239: char *tmp_name;
241: PetscCall(PetscStrallocpy(name, &tmp_name));
242: PetscCall(PetscHMapFuncSet(map, tmp_name, fnc));
243: }
244: } else if (found) {
245: const char *tmp_name;
247: PetscHashIterGetKey(map, it, tmp_name);
248: PetscCall(PetscFree(tmp_name));
249: PetscCall(PetscHMapFuncIterDel(map, it));
250: }
251: PetscFunctionReturn(PETSC_SUCCESS);
252: }
254: static PetscErrorCode PetscFunctionListCreate_Private(PetscInt size, PetscFunctionList *fl)
255: {
256: PetscFunctionBegin;
257: if (*fl) PetscFunctionReturn(PETSC_SUCCESS);
258: PetscCall(PetscNew(fl));
259: PetscCall(PetscHMapFuncCreateWithSize(size, &(*fl)->map));
260: PetscCall(PetscFunctionListDLAllPush_Private(*fl));
261: PetscFunctionReturn(PETSC_SUCCESS);
262: }
264: /*MC
265: PetscFunctionListAdd - Given a routine and a string id, saves that routine in the
266: specified registry.
268: Synopsis:
269: #include <petscsys.h>
270: PetscErrorCode PetscFunctionListAdd(PetscFunctionList *flist,const char name[],void (*fptr)(void))
272: Not Collective
274: Input Parameters:
275: + flist - pointer to function list object
276: . name - string to identify routine
277: - fptr - function pointer
279: Level: developer
281: Notes:
282: To remove a registered routine, pass in a `NULL` `fptr`.
284: Users who wish to register new classes for use by a particular PETSc
285: component (e.g., `SNES`) should generally call the registration routine
286: for that particular component (e.g., `SNESRegister()`) instead of
287: calling `PetscFunctionListAdd()` directly.
289: .seealso: `PetscFunctionListDestroy()`, `SNESRegister()`, `KSPRegister()`,`PetscFunctionListDuplicate()`
290: `PCRegister()`, `TSRegister()`, `PetscFunctionList`, `PetscObjectComposeFunction()`
291: M*/
292: PetscErrorCode PetscFunctionListAdd_Private(PetscFunctionList *fl, const char name[], PetscVoidFunction fnc)
293: {
294: PetscFunctionBegin;
298: PetscCall(PetscFunctionListCreate_Private(0, fl));
299: PetscCall(PetscHMapFuncInsert_Private((*fl)->map, name, fnc));
300: PetscFunctionReturn(PETSC_SUCCESS);
301: }
303: /*@
304: PetscFunctionListDestroy - Destroys a list of registered routines.
306: Input Parameter:
307: . fl - pointer to list
309: Level: developer
311: .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`, `PetscFunctionListClear()`
312: @*/
313: PetscErrorCode PetscFunctionListDestroy(PetscFunctionList *fl)
314: {
315: PetscFunctionBegin;
316: if (!*fl) PetscFunctionReturn(PETSC_SUCCESS);
317: PetscCall(PetscFunctionListDLAllPop_Private(*fl));
318: /* free this list */
319: PetscCall(PetscFunctionListClear(*fl));
320: PetscCall(PetscHMapFuncDestroy(&(*fl)->map));
321: PetscCall(PetscFree(*fl));
322: PetscFunctionReturn(PETSC_SUCCESS);
323: }
325: #define PetscHMapFuncForEach(__func_list__, __key_name__, __val_name__, ...) \
326: do { \
327: const PetscHMapFunc phmfi_map_ = (__func_list__)->map; \
328: PetscHashIter phmfi_iter_; \
329: \
330: PetscHashIterBegin(phmfi_map_, phmfi_iter_); \
331: while (!PetscHashIterAtEnd(phmfi_map_, phmfi_iter_)) { \
332: const char *PETSC_UNUSED __key_name__; \
333: PetscVoidFunction PETSC_UNUSED __val_name__; \
334: \
335: PetscHashIterGetKey(phmfi_map_, phmfi_iter_, __key_name__); \
336: PetscHashIterGetVal(phmfi_map_, phmfi_iter_, __val_name__); \
337: { \
338: __VA_ARGS__; \
339: } \
340: PetscHashIterNext(phmfi_map_, phmfi_iter_); \
341: } /* end while */ \
342: } while (0)
344: /*@
345: PetscFunctionListClear - Clear a `PetscFunctionList`
347: Not Collective
349: Input Parameter:
350: . fl - The `PetscFunctionList` to clear
352: Level: developer
354: Notes:
355: This clears the contents of `fl` but does not deallocate the entries themselves.
357: .seealso: `PetscFunctionList`, `PetscFunctionListDestroy()`, `PetscFunctionListAdd()`
358: @*/
359: PetscErrorCode PetscFunctionListClear(PetscFunctionList fl)
360: {
361: PetscFunctionBegin;
362: if (fl) {
363: PetscHMapFuncForEach(fl, name, func, PetscCall(PetscFree(name)));
364: PetscCall(PetscHMapFuncClear(fl->map));
365: }
366: PetscFunctionReturn(PETSC_SUCCESS);
367: }
369: /*
370: Print registered PetscFunctionLists
371: */
372: PetscErrorCode PetscFunctionListPrintAll(void)
373: {
374: PetscFunctionListDLAll current = dlallhead;
376: PetscFunctionBegin;
377: if (current) PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d] Registered PetscFunctionLists\n", PetscGlobalRank));
378: while (current) {
379: PetscCall(PetscFunctionListPrintNonEmpty(current->data));
380: current = current->next;
381: }
382: PetscFunctionReturn(PETSC_SUCCESS);
383: }
385: /*MC
386: PetscFunctionListNonEmpty - Print composed names for non `NULL` function pointers
388: Input Parameter:
389: . flist - pointer to list
391: Level: developer
393: .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`, `PetscObjectQueryFunction()`
394: M*/
395: PetscErrorCode PetscFunctionListPrintNonEmpty(PetscFunctionList fl)
396: {
397: PetscFunctionBegin;
398: if (fl) {
399: // clang-format off
400: PetscHMapFuncForEach(
401: fl,
402: name, func,
403: PetscCall(PetscFPrintf(PETSC_COMM_SELF, PETSC_STDOUT, "[%d] function name: %s\n", PetscGlobalRank, name));
404: );
405: // clang-format on
406: }
407: PetscFunctionReturn(PETSC_SUCCESS);
408: }
410: /*MC
411: PetscFunctionListFind - Find function registered under given name
413: Synopsis:
414: #include <petscsys.h>
415: PetscErrorCode PetscFunctionListFind(PetscFunctionList flist,const char name[],void (**fptr)(void))
417: Input Parameters:
418: + flist - pointer to list
419: - name - name registered for the function
421: Output Parameter:
422: . fptr - the function pointer if name was found, else `NULL`
424: Level: developer
426: .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`, `PetscObjectQueryFunction()`, `PetscFunctionListDuplicate()`
427: M*/
428: PetscErrorCode PetscFunctionListFind_Private(PetscFunctionList fl, const char name[], PetscVoidFunction *r)
429: {
430: PetscFunctionBegin;
433: *r = NULL;
434: if (fl) PetscCall(PetscHMapFuncGet(fl->map, name, r));
435: PetscFunctionReturn(PETSC_SUCCESS);
436: }
438: /*@
439: PetscFunctionListView - prints out contents of a `PetscFunctionList`
441: Collective
443: Input Parameters:
444: + list - the list of functions
445: - viewer - the `PetscViewer` used to view the `PetscFunctionList`
447: Level: developer
449: .seealso: `PetscFunctionListAdd()`, `PetscFunctionListPrintTypes()`, `PetscFunctionList`
450: @*/
451: PetscErrorCode PetscFunctionListView(PetscFunctionList list, PetscViewer viewer)
452: {
453: PetscBool iascii;
455: PetscFunctionBegin;
457: if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PETSC_COMM_SELF, &viewer));
460: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
461: PetscCheck(iascii, PETSC_COMM_SELF, PETSC_ERR_SUP, "Only ASCII viewer supported");
462: {
463: PetscInt size;
465: PetscCall(PetscHMapFuncGetSize(list->map, &size));
466: PetscCall(PetscViewerASCIIPrintf(viewer, "PetscFunctionList Object:\n"));
467: PetscCall(PetscViewerASCIIPushTab(viewer));
468: PetscCall(PetscViewerASCIIPrintf(viewer, "size: %" PetscInt_FMT "\n", size));
469: if (size) {
470: PetscInt count = 0;
472: PetscCall(PetscViewerASCIIPrintf(viewer, "functions:\n"));
473: PetscCall(PetscViewerASCIIPushTab(viewer));
474: PetscHMapFuncForEach(list, name, func, PetscCall(PetscViewerASCIIPrintf(viewer, "%" PetscInt_FMT ": %s\n", ++count, name)));
475: PetscCall(PetscViewerASCIIPopTab(viewer));
476: }
477: PetscCall(PetscViewerASCIIPopTab(viewer));
478: }
479: PetscFunctionReturn(PETSC_SUCCESS);
480: }
482: /*@C
483: PetscFunctionListGet - Gets an array the contains the entries in `PetscFunctionList`, this is used
484: by help etc.
486: Not Collective
488: Input Parameter:
489: . list - list of types
491: Output Parameters:
492: + array - array of names
493: - n - length of `array`
495: Level: developer
497: Note:
498: This allocates the array so that must be freed. BUT the individual entries are
499: not copied so should not be freed.
501: .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`
502: @*/
503: PetscErrorCode PetscFunctionListGet(PetscFunctionList list, const char ***array, int *n)
504: {
505: PetscInt size = 0;
507: PetscFunctionBegin;
509: *array = NULL;
510: if (list) {
511: const PetscHMapFunc map = list->map;
512: PetscInt off = 0;
514: PetscCall(PetscHMapFuncGetSize(map, &size));
515: PetscCall(PetscMalloc1(size, (char ***)array));
516: PetscCall(PetscHMapFuncGetKeys(map, &off, *array));
517: }
518: *n = (int)size;
519: PetscFunctionReturn(PETSC_SUCCESS);
520: }
522: /*@C
523: PetscFunctionListPrintTypes - Prints the methods available in a list of functions
525: Collective over MPI_Comm
527: Input Parameters:
528: + comm - the communicator (usually `MPI_COMM_WORLD`)
529: . fd - file to print to, usually `stdout`
530: . prefix - prefix to prepend to name (optional)
531: . name - option string (for example, `-ksp_type`)
532: . text - short description of the object (for example, "Krylov solvers")
533: . man - name of manual page that discusses the object (for example, `KSPCreate`)
534: . list - list of types
535: . def - default (current) value
536: - newv - new value
538: Level: developer
540: .seealso: `PetscFunctionListAdd()`, `PetscFunctionList`
541: @*/
542: PetscErrorCode PetscFunctionListPrintTypes(MPI_Comm comm, FILE *fd, const char prefix[], const char name[], const char text[], const char man[], PetscFunctionList list, const char def[], const char newv[])
543: {
544: char p[64];
546: PetscFunctionBegin;
547: (void)fd;
548: PetscCall(PetscStrncpy(p, "-", sizeof(p)));
549: if (prefix) PetscCall(PetscStrlcat(p, prefix, sizeof(p)));
550: PetscCall((*PetscHelpPrintf)(comm, " %s%s <now %s : formerly %s>: %s (one of)", p, name + 1, newv, def, text));
552: if (list) PetscHMapFuncForEach(list, name, func, PetscCall((*PetscHelpPrintf)(comm, " %s", name)));
553: PetscCall((*PetscHelpPrintf)(comm, " (%s)\n", man));
554: PetscFunctionReturn(PETSC_SUCCESS);
555: }
557: /*@
558: PetscFunctionListDuplicate - Creates a new list from a given function list `PetscFunctionList`.
560: Input Parameter:
561: . fl - pointer to list
563: Output Parameter:
564: . nl - the new list (should point to `NULL` to start, otherwise appends)
566: Level: developer
568: .seealso: `PetscFunctionList`, `PetscFunctionListAdd()`, `PetscFlistDestroy()`
569: @*/
570: PetscErrorCode PetscFunctionListDuplicate(PetscFunctionList fl, PetscFunctionList *nl)
571: {
572: PetscFunctionBegin;
573: if (fl) {
574: PetscHMapFunc dup_map;
576: if (!*nl) {
577: PetscInt n;
579: PetscCall(PetscHMapFuncGetSize(fl->map, &n));
580: PetscCall(PetscFunctionListCreate_Private(n, nl));
581: }
582: dup_map = (*nl)->map;
583: PetscHMapFuncForEach(fl, name, func, PetscCall(PetscHMapFuncInsert_Private(dup_map, name, func)));
584: }
585: PetscFunctionReturn(PETSC_SUCCESS);
586: }