Actual source code: sysshell.c
petsc-3.3-p7 2013-05-11
1: #include <petscsys.h>
3: /* FIX: is it okay to include this directly? */
4: #include <ctype.h>
6: PetscClassId PETSC_SHELL_CLASSID;
7: static char PETSC_SHELL_CLASS_NAME[] = "PetscShell";
8: static PetscBool PetscShellPackageInitialized = PETSC_FALSE;
11: typedef PetscErrorCode (*PetscShellPythonLoadVTableFunction)(PetscShell shell, const char* path, const char* name, void **vtable);
12: typedef PetscErrorCode (*PetscShellPythonClearVTableFunction)(PetscShell shell, void **vtable);
13: typedef PetscErrorCode (*PetscShellPythonCallFunction)(PetscShell shell, const char* message, void *vtable);
15: EXTERN_C_BEGIN
16: PetscShellPythonLoadVTableFunction PetscShellPythonLoadVTable = PETSC_NULL;
17: PetscShellPythonClearVTableFunction PetscShellPythonClearVTable = PETSC_NULL;
18: PetscShellPythonCallFunction PetscShellPythonCall = PETSC_NULL;
19: EXTERN_C_END
21: #define PETSC_SHELL_CHECKINIT_PYTHON() \
22: if(PetscShellPythonLoadVTable == PETSC_NULL) { \
24: PetscPythonInitialize(PETSC_NULL,PETSC_NULL); \
25: if(PetscShellPythonLoadVTable == PETSC_NULL) { \
26: SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB, \
27: "Couldn't initialize Python support for PetscShell"); \
28: } \
29: }
30:
31: #define PETSC_SHELL_LOAD_VTABLE_PYTHON(shell, path, name) \
32: PETSC_SHELL_CHECKINIT_PYTHON(); \
33: { \
35: PetscShellPythonLoadVTable(shell, path, name, &(shell->vtable)); \
36: if (ierr) { PetscPythonPrintError(); SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB, "Python error"); } \
37: }
39: #define PETSC_SHELL_CLEAR_VTABLE_PYTHON(shell) \
40: PETSC_SHELL_CHECKINIT_PYTHON(); \
41: { \
43: PetscShellPythonClearVTable(shell, &(shell->vtable)); \
44: if (ierr) { PetscPythonPrintError(); SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB, "Python error"); } \
45: }
46:
47: #define PETSC_SHELL_CALL_PYTHON(shell, message) \
48: PETSC_SHELL_CHECKINIT_PYTHON(); \
49: { \
51: PetscShellPythonCall(shell, message, shell->vtable); \
52: if (ierr) { PetscPythonPrintError(); SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB, "Python error"); } \
53: }
54:
56: /* ---------------------------------------------------------------------------------------------- */
57: struct _n_PetscShellGraph {
58: PetscInt vcount, vmax; /* actual and allocated number of vertices */
59: PetscInt *i, *j, *outdegree; /* (A)IJ structure for the underlying matrix:
60: i[row] the row offset into j,
61: i[row+1] - i[row] allocated number of entries for row,
62: outdegree[row] actual number of entries in row
63: */
64: PetscInt *indegree;
65: PetscInt nz, maxnz;
66: PetscInt rowreallocs, colreallocs;
67: };
69: typedef struct _n_PetscShellGraph *PetscShellGraph;
71: #define CHUNKSIZE 5
72: /*
73: Inserts the (row,col) entry, allocating larger arrays, if necessary.
74: Does NOT check whether row and col are within range (< graph->vcount).
75: Does NOT check whether the entry is already present.
76: */
77: #undef __FUNCT__
79: PetscErrorCode PetscShellGraphExpandRow_Private(PetscShellGraph graph, PetscInt row)
80: {
82: PetscInt rowlen, rowmax, rowoffset;
83: PetscInt ii;
86: rowlen = graph->outdegree[row];
87: rowmax = graph->i[row+1] - graph->i[row];
88: rowoffset = graph->i[row];
89: if (rowlen >= rowmax) {
90: /* there is no extra room in row, therefore enlarge */
91: PetscInt new_nz = graph->i[graph->vcount] + CHUNKSIZE;
92: PetscInt *new_i=0,*new_j=0;
93:
94: /* malloc new storage space */
95: PetscMalloc(new_nz*sizeof(PetscInt),&new_j);
96: PetscMalloc((graph->vmax+1)*sizeof(PetscInt),&new_i);
97:
98: /* copy over old data into new slots */
99: for (ii=0; ii<row+1; ii++) {new_i[ii] = graph->i[ii];}
100: for (ii=row+1; ii<graph->vmax+1; ii++) {new_i[ii] = graph->i[ii]+CHUNKSIZE;}
101: PetscMemcpy(new_j,graph->j,(rowoffset+rowlen)*sizeof(PetscInt));
102: PetscMemcpy(new_j+rowoffset+rowlen+CHUNKSIZE,graph->j+rowoffset+rowlen,(new_nz - CHUNKSIZE - rowoffset - rowlen)*sizeof(PetscInt));
103: /* free up old matrix storage */
104: PetscFree(graph->j);
105: PetscFree(graph->i);
106: graph->i = new_i; graph->j = new_j;
107: graph->maxnz += CHUNKSIZE;
108: graph->colreallocs++;
109: }
110: return(0);
111: }/* PetscShellGraphExpandRow_Private() */
113: #undef __FUNCT__
115: PetscErrorCode PetscShellGraphAddVertex(PetscShellGraph graph, PetscInt *v) {
116: PetscInt ii;
119: if(graph->vcount >= graph->vmax) {
120: /* Add rows */
121: PetscInt *new_i=0, *new_outdegree=0, *new_indegree;
122:
123: /* malloc new storage space */
124: PetscMalloc((graph->vmax+CHUNKSIZE+1)*sizeof(PetscInt),&new_i);
125: PetscMalloc((graph->vmax+CHUNKSIZE)*sizeof(PetscInt),&new_outdegree);
126: PetscMalloc((graph->vmax+CHUNKSIZE)*sizeof(PetscInt),&new_indegree);
127: PetscMemzero(new_outdegree, (graph->vmax+CHUNKSIZE)*sizeof(PetscInt));
128: PetscMemzero(new_indegree, (graph->vmax+CHUNKSIZE)*sizeof(PetscInt));
131: /* copy over old data into new slots */
132: PetscMemcpy(new_i,graph->i,(graph->vmax+1)*sizeof(PetscInt));
133: PetscMemcpy(new_outdegree,graph->outdegree,(graph->vmax)*sizeof(PetscInt));
134: PetscMemcpy(new_indegree,graph->indegree,(graph->vmax)*sizeof(PetscInt));
135: for (ii=graph->vmax+1; ii<=graph->vmax+CHUNKSIZE; ++ii) {
136: new_i[ii] = graph->i[graph->vmax];
137: }
139: /* free up old matrix storage */
140: PetscFree(graph->i);
141: PetscFree(graph->outdegree);
142: PetscFree(graph->indegree);
143: graph->i = new_i; graph->outdegree = new_outdegree; graph->indegree = new_indegree;
144:
145: graph->vmax += CHUNKSIZE;
146: graph->rowreallocs++;
147: }
148: if(v) {*v = graph->vcount;}
149: ++(graph->vcount);
150: return(0);
151: }/* PetscShellGraphAddVertex() */
153: #undef __FUNCT__
155: PetscErrorCode PetscShellGraphAddEdge(PetscShellGraph graph, PetscInt row, PetscInt col) {
156: PetscErrorCode ierr;
157: PetscInt *rp,low,high,t,ii,i;
160: if(row < 0 || row >= graph->vcount) {
161: SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Source vertex %D out of range: min %D max %D",row, 0, graph->vcount);
162: }
163: if(col < 0 || col >= graph->vcount) {
164: SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Target vertex %D out of range: min %D max %D",col, 0, graph->vcount);
165: }
166: rp = graph->j + graph->i[row];
167: low = 0;
168: high = graph->outdegree[row];
169: while (high-low > 5) {
170: t = (low+high)/2;
171: if (rp[t] > col) high = t;
172: else low = t;
173: }
174: for (i=low; i<high; ++i) {
175: if (rp[i] > col) break;
176: if (rp[i] == col) {
177: goto we_are_done;
178: }
179: }
180: PetscShellGraphExpandRow_Private(graph, row);
181: /*
182: If the graph was empty before, graph->j was NULL and rp was NULL as well.
183: Now that the row has been expanded, rp needs to be reset.
184: */
185: rp = graph->j + graph->i[row];
186: /* shift up all the later entries in this row */
187: for (ii=graph->outdegree[row]; ii>=i; --ii) {
188: rp[ii+1] = rp[ii];
189: }
190: rp[i] = col;
191: ++(graph->outdegree[row]);
192: ++(graph->indegree[col]);
193: ++(graph->nz);
194:
195: we_are_done:
196: return(0);
197: }/* PetscShellGraphAddEdge() */
200: #undef __FUNCT__
202: PetscErrorCode PetscShellGraphTopologicalSort(PetscShellGraph graph, PetscInt *n, PetscInt **queue) {
203: PetscBool *queued;
204: PetscInt *indegree;
205: PetscInt ii, k, jj, Nqueued = 0;
206: PetscBool progress;
209: if(!n || !queue) {
210: SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG, "Invalid return argument pointers n or vertices");
211: }
212: *n = graph->vcount;
213: PetscMalloc(sizeof(PetscInt)*graph->vcount, queue);
214: PetscMalloc(sizeof(PetscBool)*graph->vcount, &queued);
215: PetscMalloc(sizeof(PetscInt)*graph->vcount, &indegree);
216: for(ii = 0; ii < graph->vcount; ++ii) {
217: queued[ii] = PETSC_FALSE;
218: indegree[ii] = graph->indegree[ii];
219: }
220: while(Nqueued < graph->vcount) {
221: progress = PETSC_FALSE;
222: for(ii = 0; ii < graph->vcount; ++ii) {
223: /* If ii is not queued yet, and the indegree is 0, queue it. */
224: if(!queued[ii] && !indegree[ii]) {
225: (*queue)[Nqueued] = ii;
226: queued[ii] = PETSC_TRUE;
227: ++Nqueued;
228: progress = PETSC_TRUE;
229: /* Reduce the indegree of all vertices in row ii */
230: for(k = 0; k < graph->outdegree[ii]; ++k) {
231: jj = graph->j[graph->i[ii]+k];
232: --(indegree[jj]);
233: /*
234: It probably would be more efficient to make a recursive call to the body of the for loop
235: with the jj in place of ii, but we use a simple-minded algorithm instead, since the graphs
236: we anticipate encountering are tiny.
237: */
238: }/* for(k) */
239: }/* if(!queued) */
240: }/* for(ii) */
241: /* If no progress was made during this iteration, the graph must have a cycle */
242: if(!progress) {
243: SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE, "Cycle detected in the dependency graph");
244: }
245: }/* while(Nqueued) */
246: PetscFree(queued);
247: PetscFree(indegree);
248: return(0);
249: }/* PetscShellGraphTopologicalSort() */
251: #undef __FUNCT__
253: PetscErrorCode PetscShellGraphDestroy(PetscShellGraph graph)
254: {
257: PetscFree(graph->i);
258: PetscFree(graph->j);
259: PetscFree(graph->outdegree);
260: PetscFree(graph->indegree);
261: PetscFree(graph);
262: return(0);
263: }/* PetscShellGraphDestroy() */
265: #undef __FUNCT__
267: PetscErrorCode PetscShellGraphCreate(PetscShellGraph *graph_p)
268: {
269: PetscShellGraph graph;
272: PetscNew(struct _n_PetscShellGraph, graph_p);
273: graph = *graph_p;
274: graph->vcount = graph->vmax = graph->nz = graph->maxnz = graph->rowreallocs = graph->colreallocs = 0;
275: PetscMalloc(sizeof(PetscInt), &(graph->i));
276: graph->j = graph->outdegree = graph->indegree = PETSC_NULL;
277: return(0);
278: }/* PetscShellGraphCreate() */
282: /* ------------------------------------------------------------------------------------------------------- */
284: typedef enum{PETSC_SHELL_VTABLE_NONE, PETSC_SHELL_VTABLE_SO, PETSC_SHELL_VTABLE_PY} PetscShellVTableType;
286: struct _n_PetscShellVTable_SO {
287: char *path, *name;
288: };
291: struct _p_PetscShell {
292: PETSCHEADER(int);
293: PetscShellVTableType vtable_type;
294: void *vtable;
295: char * url;
296: PetscShell visitor;
297: PetscInt N, maxN;
298: char ** key;
299: PetscShell *component;
300: PetscShellGraph dep_graph;
301: };
306: /* ------------------------------------------------------------------------------------------------------- */
308: typedef PetscErrorCode (*PetscShellCallFunction)(PetscShell, const char*);
309: typedef PetscErrorCode (*PetscShellMessageFunction)(PetscShell);
310: typedef void (*QueryFunction)(void);
312: static PetscDLLibrary PetscShellDLLibrariesLoaded = 0;
314: #undef __FUNCT__
316: PetscErrorCode PetscShellCall_SO(PetscShell shell, const char* path, const char* name, const char* message) {
317: size_t namelen, messagelen, msgfunclen, callfunclen;
318: char *msgfunc = PETSC_NULL, *callfunc = PETSC_NULL;
319: PetscShellCallFunction call = PETSC_NULL;
320: PetscShellMessageFunction msg = PETSC_NULL;
323: PetscStrlen(name, &namelen);
324: PetscStrlen(message, &messagelen);
325: msgfunclen = namelen + messagelen;
326: PetscMalloc(sizeof(char)*(msgfunclen+1), &msgfunc);
327: msgfunc[0] = '\0';
328: if(namelen){
329: PetscStrcat(msgfunc, name);
330: }
331: PetscStrcat(msgfunc, message);
332: if(namelen) {
333: /* HACK: is 'toupper' part of the C standard? Looks like starting with C89. */
334: msgfunc[namelen] = toupper(msgfunc[namelen]);
335: }
336: PetscDLLibrarySym(((PetscObject)shell)->comm, &PetscShellDLLibrariesLoaded, path, msgfunc, (void **)(&msg));
337: PetscFree(msgfunc);
338: if(msg) {
339: (*msg)(shell);
340: return(0);
341: }
342: callfunclen = namelen+4;
343: PetscMalloc(sizeof(char)*(callfunclen+1), &callfunc);
344: if(namelen) {
345: PetscStrcpy(callfunc, name);
346: }
347: if(namelen){
348: PetscStrcat(callfunc, "Call");
349: }
350: else {
351: PetscStrcat(callfunc, "call");
352: }
353: PetscDLLibrarySym(((PetscObject)shell)->comm, &PetscShellDLLibrariesLoaded, path, callfunc, (void**)(&call));
354: PetscFree(callfunc);
355: if(call) {
356: (*call)(shell, message);
357: return(0);
358: }
359: SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "PetscShell '%s' cannot execute '%s'", ((PetscObject)shell)->name, message);
360: return(0);
361: }/* PetscShellCall_SO() */
364: #undef __FUNCT__
366: PetscErrorCode PetscShellCall_NONE(PetscShell shell, const char* message) {
367: PetscShellCallFunction call = PETSC_NULL;
368: PetscShellMessageFunction msg = PETSC_NULL;
371: PetscFListFind(((PetscObject)shell)->qlist, ((PetscObject)shell)->comm, message,PETSC_FALSE, (QueryFunction*)(&msg));
372: if(msg) {
373: (*msg)(shell);
374: return(0);
375: }
376: PetscFListFind(((PetscObject)shell)->qlist, ((PetscObject)shell)->comm, "call",PETSC_FALSE, (QueryFunction*)(&call));
377: if(call) {
378: (*call)(shell, message);
379: return(0);
380: }
381: SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "PetscShell '%s' cannot execute '%s'", ((PetscObject)shell)->name, message);
382: return(0);
383: }/* PetscShellCall_NONE() */
386: #undef __FUNCT__
388: /*@C
389: PetscShellCall -- send a string message to a PetscShell object.
391: Logically collective on PetscShell.
393: Input paramters:
394: + shell -- a PetscShell object
395: - message -- a character string
397: Notes: In response to the message the object performs actions defined by its URL (see PetscShellSetURL()).
398: Side effects may include, in particular, actions on the composed objects (see PetscObjectCompose()).
400: Level: intermediate.
402: .seealso: PetscShellSetURL(), PetscShellGetURL(), PetscObjectCompose(), PetscObjectQuery()
403: @*/
404: PetscErrorCode PetscShellCall(PetscShell shell, const char* message) {
409: if(!message || !message[0]) {
410: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Null or empty message string");
411: }
412: switch(shell->vtable_type) {
413: case PETSC_SHELL_VTABLE_NONE:
414: PetscShellCall_NONE(shell, message);
415: break;
416: case PETSC_SHELL_VTABLE_SO:
417: PetscShellCall_SO(shell,
418: ((struct _n_PetscShellVTable_SO*)shell->vtable)->path,
419: ((struct _n_PetscShellVTable_SO*)shell->vtable)->name,
420: message);
421:
422: break;
423: case PETSC_SHELL_VTABLE_PY:
424: PETSC_SHELL_CALL_PYTHON(shell, message);
425: break;
426: default:
427: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown PetscShellVTableType value");
428: break;
429: }
430: return(0);
431: }/* PetscShellCall() */
434: #define PETSC_SHELL_MAX_URL_LENGTH 1024
435: /*
436: Normalize the url (by truncating to PETSC_SHELL_MAX_URL_LENGTH) and parse it to find out the component type and location.
437: Warning: the returned char pointers are borrowed and their contents must be copied elsewhere to be preserved.
438: */
439: #undef __FUNCT__
441: PetscErrorCode PetscShellParseURL_Private(const char inurl[], char **outpath, char **outname, PetscShellVTableType *outtype){
442: char *n, *s;
443: static PetscInt nlen = PETSC_SHELL_MAX_URL_LENGTH;
444: static char path[PETSC_SHELL_MAX_URL_LENGTH+1], name[PETSC_SHELL_MAX_URL_LENGTH+1];
445: PetscShellVTableType type = PETSC_SHELL_VTABLE_NONE;
448: /* FIX: this routine should replace the filesystem path by an abolute path for real normalization */
449: /* Copy the inurl so we can manipulate it inplace and also truncate to the max allowable length */
450: PetscStrncpy(path, inurl, nlen);
451: /* Split url <path>:<name> into <path> and <name> */
452: PetscStrrchr(path,':',&n);
453: /* Make sure it's not the ":/" of the "://" separator */
454: if(!n[0] || n[0] == '/') {
455: SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,
456: "Could not locate component name within the URL.\n"
457: "Must have url = [<path/><library>:]<name>.\n"
458: "Instead got %s\n"
459: "Remember that URL is always truncated to the max allowed length of %d",
460: inurl, nlen);
461: }
462: /* Copy n to name */
463: PetscStrcpy(name, n);
464: /* If n isn't the whole path (i.e., there is a ':' separator), end 'path' right before the located ':' */
465: if(n == path) {
466: /*
467: No library is provided, so the component is assumed to be "local", that is
468: defined in an already loaded executable. So we set type to .so, path to "",
469: and look for the configure symbol among already loaded symbols
470: (or count on PetscDLXXX to do that.
471: */
472: type = PETSC_SHELL_VTABLE_SO;
473: path[0] = '\0';
474: }
475: else {
476: n[-1] = '\0';
477: /* Find the library suffix and determine the component library type: .so or .py */
478: PetscStrrchr(path,'.',&s);
479: /* FIX: we should really be using PETSc's internally defined suffices */
480: if(s != path && s[-1] == '.') {
481: if((s[0] == 'a' && s[1] == '\0') || (s[0] == 's' && s[1] == 'o' && s[2] == '\0')){
482: type = PETSC_SHELL_VTABLE_SO;
483: }
484: else if (s[0] == 'p' && s[1] == 'y' && s[2] == '\0'){
485: type = PETSC_SHELL_VTABLE_PY;
486: }
487: else {
488: SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,
489: "Unknown library suffix within the URL.\n"
490: "Must have url = [<path/><library>:]<name>,\n"
491: "where library = <libname>.<suffix>, suffix = .a || .so || .py.\n"
492: "Instead got url %s\n"
493: "Remember that URL is always truncated to the max allowed length of %d",
494: inurl, s,nlen);
495: }
496: }
497: }
498: *outpath = path;
499: *outname = name;
500: *outtype = type;
501: return(0);
502: }/* PetscShellParseURL_Private() */
504: #undef __FUNCT__
506: PetscErrorCode PetscShellClearURL_Private(PetscShell shell) {
509: switch(shell->vtable_type) {
510: case PETSC_SHELL_VTABLE_SO:
511: {
512: struct _n_PetscShellVTable_SO *vt = (struct _n_PetscShellVTable_SO*)(shell->vtable);
513: PetscFree(vt->path);
514: PetscFree(vt->name);
515: PetscFree(vt);
516: shell->vtable = PETSC_NULL;
517: shell->vtable_type = PETSC_SHELL_VTABLE_NONE;
518: }
519: break;
520: case PETSC_SHELL_VTABLE_PY:
521: PETSC_SHELL_CLEAR_VTABLE_PYTHON(shell);
522: break;
523: case PETSC_SHELL_VTABLE_NONE:
524: break;
525: default:
526: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,
527: "Unknown PetscShell vtable type: %d", shell->vtable_type);
528: }
529: PetscFree(shell->url);
530: shell->url = PETSC_NULL;
531: return(0);
532: }/* PetscShellClearURL_Private() */
534: #undef __FUNCT__
536: /*@C
537: PetscShellSetURL -- set a backend implementing PetscShell functionality from the URL string.
539: Logically collective on PetscShell.
541: Input paramters:
542: + shell -- a PetscShell object
543: - url -- URL string
545: Notes: URL can point to a backend -- a .so file or a .py file.
546: A .so URL must have the form [<path>/<lib>.a:]<name> or [<path>/<lib>.so:]<name>, and the .a or the .so
547: file must contain symbols for function 'void <name>Call(const char[])' or symbols 'void <name><Message>(void)'
548: for any <message> that PetscShell is expected to understand. When PetscShellCall() is invoked
549: with <message>, a symbol for 'void name<Message>(void)' is sought and called, if found. If not, a symbol for
550: 'void <name>Call(const char[])' is sought and called with <message> as the argument. If neither symbol is found,
551: an error occurs.
552: A .py URL must have the form <path>/<module>.py:<name>, and the .py file must define a class <name>
553: that implements 'call(str)' or '<message>()' methods, as above.
554: If no URL has been set, shell attempts to respond to the message using function '<message>', and, failing that,
555: using function 'call' with argument <message>; the functions are retrieved from shell using PetscObjectQueryFunction().
556: If neither '<message>' nor 'call' have been previusly composed with shell (see PetscObjectComposeFunction()), an error
557: occurs.
559: Level: intermediate.
561: .seealso: PetscShellGetURL(), PetscObjectCompose(), PetscObjectQuery(), PetscObjectComposeFunction(), PetscShellCall()
562: @*/
563: PetscErrorCode PetscShellSetURL(PetscShell shell, const char url[]) {
565: char *path, *name;
569: if(shell->vtable) {
570: PetscShellClearURL_Private(shell);
571: }
572: PetscStrallocpy(url, &(shell->url));
573: PetscShellParseURL_Private(url, &path, &name, &shell->vtable_type);
574: switch(shell->vtable_type) {
575: case PETSC_SHELL_VTABLE_SO:
576: {
577: struct _n_PetscShellVTable_SO *vt;
578: PetscMalloc(sizeof(struct _n_PetscShellVTable_SO), &(vt));
579: shell->vtable = (void*)vt;
580: PetscStrallocpy(path, &vt->path);
581: PetscStrallocpy(name, &vt->name);
582: }
583: break;
584: case PETSC_SHELL_VTABLE_PY:
585: PETSC_SHELL_LOAD_VTABLE_PYTHON(shell, path, name);
586: break;
587: default:
588: SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,
589: "Unknown PetscShell vtable type: %d", shell->vtable_type);
590: }
591: return(0);
592: }/* PetscShellSetURL() */
595: #undef __FUNCT__
597: /*@C
598: PetscShellGetURL -- retrieve the URL defining the backend that implements the PetscShellCall() functionality.
600: Not collective.
602: Input paramters:
603: . shell -- a PetscShell object
605: Output parameters:
606: . url -- the URL string
608: Level: beginner.
610: .seealso: PetscShellSetURL(), PetscShellCall()
611: @*/
612: PetscErrorCode PetscShellGetURL(PetscShell shell, const char **url) {
616: *url = shell->url;
617: return(0);
618: }/* PetscShellGetURL() */
619:
621: /* ------------------------------------------------------------------------------------------------------- */
622: #undef __FUNCT__
624: PetscErrorCode PetscShellView_Private(PetscShell shell, const char *key, PetscInt rank, PetscViewer viewer) {
625: PetscInt *vertices, N;
626: PetscInt i, id;
627: PetscBool iascii;
628: PetscErrorCode ierr;
631: if (!viewer) {
632: PetscViewerASCIIGetStdout(((PetscObject)shell)->comm,&viewer);
633: }
636: PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);
637: if (!iascii) {
638: SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG, "PetscShell can only be viewed with an ASCII viewer");
639: }
640: else {
641: if(!key) {
642: PetscViewerASCIIPrintf(viewer, "Shell name: %s,\turl: %s\n", ((PetscObject)shell)->name, shell->url);
643: }
644: else {
645: PetscViewerASCIIPrintf(viewer, "Component: %D,\tkey: %s, \tname: %s,\turl: %s\n", rank, key, ((PetscObject)shell)->name, shell->url);
646: }
647: PetscShellGraphTopologicalSort(shell->dep_graph, &N, &vertices);
648: if(N) {
649: PetscViewerASCIIPrintf(viewer, "Component shells in the topological order of the dependence graph:\n");
650: PetscViewerASCIIPushTab(viewer);
651: for(i = 0; i < N; ++i) {
652: id = vertices[i];
653: PetscShellView_Private(shell->component[id], shell->key[id], id, viewer);
654: }
655: PetscViewerASCIIPopTab(viewer);
656: }
657: PetscFree(vertices);
658: }
659: return(0);
660: }/* PetscShellView() */
662: #undef __FUNCT__
664: /*@C
665: PetscShellView -- print information about a PetscShell object to an ASCII viewer.
666: The information printed includes the object name, url and
667: the dependent components registered with PetscShellRegisterComponentShell(),
668: PetscShellRegisterComponentURL() or PetscShellRegisterDependence().
670: Not collective.
672: Input paramters:
673: + shell -- a PetscShell object
674: - viewer -- an ASCII PetscViewer
676: Level: beginner.
678: .seealso: PetscShellSetURL(), PetscShellRegisterComponet(), PetscShellRegisterComponentURL(), PetscShellRegisterDependence()
679: @*/
680: PetscErrorCode PetscShellView(PetscShell shell, PetscViewer viewer) {
681: PetscErrorCode ierr;
683: PetscShellView_Private(shell, 0,-1, viewer);
684: return(0);
685: }/* PetscShellView() */
687: /*@C
688: PetscShellGetVisitor -- retrieve the PetscShell object executing PetscShellVisit() on the current shell.
689: The visitor is one of the (possibly many) PetscShell objects with which shell
690: has been registered as a component using PetscShellRegisterComponentShell(),
691: PetscShellRegisterComponentURL(), or PetscShellRegisterDependence()
695: Not collective.
697: Input paramters:
698: . shell -- a PetscShell object
700: Output parameters:
701: . visitor -- the visitor PetscShell object
703: Notes: The visitor is valid only during the PetscShellVisit() and is PETSC_NULL otherwise.
705: Level: intermediate
707: .seealso: PetscShellVisit(), PetscShellCall(), PetscShellRegisterComponentShell(), PetscShellRegisterDependence()
708: @*/
709: #undef __FUNCT__
711: PetscErrorCode PetscShellGetVisitor(PetscShell shell, PetscShell *visitor)
712: {
716: *visitor = shell->visitor;
717: return(0);
718: }/* PetscShellGetVisitor() */
720: #undef __FUNCT__
722: /*@C
723: PetscShellVisit -- traverse shell's components registered with PetscShellRegisterComponentShell(), PetscShellRegisterComponentURL(),
724: or PetscShellRegisterDependence(), and executes PetscShellCall() on the components with the given message.
725: The traversal is done in the topological order defined by the graph with edges specified by PetscShellRegisterDependence()
726: calls: this way "server" components are guaranteed to be called before the "client" components.
728: Logically collective on PetscShell.
730: Input paramters:
731: + shell -- a PetscShell object
732: - message -- a character string
734: Notes: In response to the message the object performs actions defined by its URL (see PetscShellSetURL()).
735: Side effects may include, in particular, actions on the composed objects (see PetscObjectCompose()).
737: Level: intermediate.
739: .seealso: PetscShellCall(), PetscShellRegisterComponentShell(), PetscShellRegisterComponentURL(), PetscShellRegisterDependence()
740: @*/
741: PetscErrorCode PetscShellVisit(PetscShell shell, const char* message){
742: PetscInt i, id, N, *vertices;
743: PetscShell component;
748: PetscShellGraphTopologicalSort(shell->dep_graph, &N, &vertices);
749: for(i = 0; i < N; ++i) {
750: id = vertices[i];
751: component = shell->component[id];
752: /* Save the component's visitor */
753: component->visitor = shell;
754: /* Call "configure" */
755: PetscShellCall(component, message);
756: /* Clear visitor */
757: component->visitor = PETSC_NULL;
758: }
759: PetscFree(vertices);
760: return(0);
761: }/* PetscShellVisit() */
763: #undef __FUNCT__
765: PetscErrorCode PetscShellGetKeyID_Private(PetscShell shell, const char key[], PetscInt *_id, PetscBool *_found){
766: PetscInt i;
767: PetscBool eq;
770: /* Check whether a component with the given key has already been registered. */
771: if(_found){*_found = PETSC_FALSE;}
772: for(i = 0; i < shell->N; ++i) {
773: PetscStrcmp(key, shell->key[i], &eq);
774: if(eq) {
775: if(_id) {*_id = i;}
776: if(_found){*_found = PETSC_TRUE;}
777: }
778: }
779: return(0);
780: }/* PetscShellGetKeyID_Private() */
782: #undef __FUNCT__
784: PetscErrorCode PetscShellRegisterKey_Private(PetscShell shell, const char key[], PetscShell component, PetscInt *_id) {
785: PetscInt v, id;
786: PetscBool found;
789: /* Check whether a component with the given key has already been registered. */
790: PetscShellGetKeyID_Private(shell, key, &id, &found);
791: if(found) {
792: if(component) {
793: /* Replace the component with the new one. */
794: shell->component[id] = component;
795: }
796: if(_id) *_id = id;
797: return(0);
798: }
799: /* No such key found. */
800: if(!component) {
801: /* Create a new component for this key. */
802: PetscShellCreate(((PetscObject)shell)->comm, &component);
803: PetscObjectSetName((PetscObject)component, key);
804: }
805: if(shell->N >= shell->maxN) {
806: /* No more empty component slots, therefore, expand the component array */
807: PetscShell *new_components;
808: char **new_keys;
809: PetscMalloc(sizeof(PetscShell)*(shell->maxN+CHUNKSIZE), &new_components);
810: PetscMemcpy(new_components, shell->component, sizeof(PetscShell)*(shell->maxN));
811: PetscMemzero(new_components+shell->maxN,sizeof(PetscShell)*(CHUNKSIZE));
812: PetscFree(shell->component);
813: shell->component = new_components;
814: /* Expand the key array */
815: PetscMalloc(sizeof(char*)*(shell->maxN+CHUNKSIZE), &new_keys);
816: PetscMemcpy(new_keys, shell->key, sizeof(char*)*(shell->maxN));
817: PetscMemzero(new_keys+shell->maxN,sizeof(char*)*(CHUNKSIZE));
818: PetscFree(shell->key);
819: shell->key = new_keys;
820: shell->maxN += CHUNKSIZE;
821: }
822: id = shell->N;
823: ++(shell->N);
824: /* Store key and component. */
825: PetscStrallocpy(key, &(shell->key[id]));
826: shell->component[id] = component;
827: /* Add a new vertex to the dependence graph. This vertex will correspond to the newly registered component. */
828: PetscShellGraphAddVertex(shell->dep_graph, &v);
829: /* v must equal id */
830: if(v != id) {
831: SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_CORRUPT, "New dependence graph vertex %d for key %s not the same as component id %d", v, key, id);
832: }
833: if(_id) *_id = id;
834: return(0);
835: }/* PetscShellRegisterKey_Private() */
838: #undef __FUNCT__
840: /*@C
841: PetscShellRegisterComponentShell -- register a component as a component of shell, identifiable within shell by key.
842: If a component with key already exists within shell, and component is not PETSC_NULL,
843: the old component is replace.
844: If component is PETSC_NULL, and key has not been registered with PetscShell,
845: and new PetscShell component is created with key as its name, and stored in shell under key.
846: If component is PETSC_NULL, and key has already been registered with PetscShell,
847: nothing is done.
848: The component can be later obtained with a PetscShellGetComponent()
849: call, or referred to be its key in a PetscShellRegisterDependenceCall().
850: Components can be visited with a particular message using PetscShellVisit().
852: Logically collective on PetscShell.
854: Input paramters:
855: + shell -- a PetscShell object
856: . key -- a character string designating the added component.
857: - component -- a PetscShell object to add (or PETSC_NULL)
860: Level: intermediate.
862: .seealso: PetscShellGetComponent(), PetscShellRegisterComponentURL(), PetscShellRegisterDependence(), PetscShellVisit()
863: @*/
864: PetscErrorCode PetscShellRegisterComponentShell(PetscShell shell, const char key[], PetscShell component){
869: PetscShellRegisterKey_Private(shell, key, component, PETSC_NULL);
870: return(0);
871: }/* PetscShellRegisterComponentShell() */
873: #undef __FUNCT__
875: /*@C
876: PetscShellRegisterComponentURL -- register a key as a component of shell (see PetscShellRegisterComponentShell())
877: and set the given URL on the newly created component.
880: Logically collective on PetscShell.
882: Input paramters:
883: + shell -- a PetscShell object
884: . key -- a character string designating the added component.
885: - url -- a character string desigating the URL of the added component.
887: Notes: equivalent to the sequence
888: PetscShellRegisterComponentShell(shell,key,PETSC_NULL);
889: PetscShellGetComponent(shell, key, &component);
890: PetscShellSetURL(component, url);
892: Level: intermediate.
894: .seealso: PetscShellRegisterComponentShell(), PetscShellGetComponent(), PetscShellSetURL()
895: @*/
896: PetscErrorCode PetscShellRegisterComponentURL(PetscShell shell, const char key[], const char url[]){
898: PetscInt id;
903: PetscShellRegisterKey_Private(shell, key, PETSC_NULL, &id);
904: PetscShellSetURL(shell->component[id], url);
905: return(0);
906: }/* PetscShellRegisterComponentURL() */
909: #undef __FUNCT__
911: /*@C
912: PetscShellRegisterDependence -- register a dependence between shell's components designated by keys "serverkey" and "clientkey".
913: If components with such keys have not already been added to shell with PetscShellRegisterComponentShell()
914: or PetscShellComponentRegisterURL(), new components are created. During a call to PetscShellVisit()
915: the component with key "serverkey" is guaranteed to be called before "clientkey".
918: Logically collective on PetscShell.
920: Input paramters:
921: + shell -- a PetscShell object
922: . serverkey -- a character string designating the server component
923: - clientkey -- a character string desigating the client component
925: Level: intermediate.
927: .seealso: PetscShellRegisterComponentShell(), PetscShellRegisterComponentURL(), PetscShellGetComponent(), PetscShellVisit()
928: @*/
929: PetscErrorCode PetscShellRegisterDependence(PetscShell shell, const char serverkey[], const char clientkey[])
930: {
931: PetscInt clientid, serverid;
937: /* Register keys */
938: PetscShellRegisterKey_Private(shell, clientkey, PETSC_NULL, &clientid);
939: PetscShellRegisterKey_Private(shell, serverkey, PETSC_NULL, &serverid);
940: /*
941: Add the dependency edge to the dependence_graph as follows (serverurl, clienturl):
942: this means "server preceeds client", so server should be configured first.
943: */
944: PetscShellGraphAddEdge(shell->dep_graph, serverid, clientid);
945: return(0);
946: }/* PetscShellRegisterDependence() */
950: #undef __FUNCT__
952: /*@C
953: PetscShellDestroy -- destroy PetscShell.
955: Not collective.
957: Input paramters:
958: . shell -- a PetscShell object
960: Level: beginner.
962: .seealso: PetscShellCreate(), PetscShellSetURL(), PetscShellCall()
963: @*/
964: PetscErrorCode PetscShellDestroy(PetscShell *shell)
965: {
966: PetscInt i;
968:
970: if (!*shell) return(0);
972: if (--((PetscObject)(*shell))->refct > 0) return(0);
973: for(i = 0; i < (*shell)->N; ++i){
974: PetscObjectDestroy((PetscObject*)&(*shell)->component[i]);
975: }
976: PetscFree((*shell)->component);
977: PetscShellGraphDestroy((*shell)->dep_graph);
978: PetscHeaderDestroy(shell);
979: return(0);
980: }/* PetscShellDestroy()*/
982: #undef __FUNCT__
984: /*@C
985: PetscShellCreate -- create an empty PetscShell object.
987: Logically collective on comm.
989: Input paramters:
990: . comm -- the MPI_Comm to create the PetscShell object on.
992: Output parameters:
993: . shell -- the created PetscShell object.
995: Notes: the default shell corresponding to PETSC_COMM_WORLD is PETSC_SHELL_DEFAULT_WORLD.
996: Likewise for PETSC_COMM_SELF and PETSC_SHELL_DEFAULT_SELF.
998: Level: beginner.
1000: .seealso: PetscShellDestroy(), PetscShellSetURL(), PetscShellCall()
1001: @*/
1002: PetscErrorCode PetscShellCreate(MPI_Comm comm, PetscShell *shell){
1003: PetscShell shell_;
1006: #ifndef PETSC_USE_DYNAMIC_LIBRARIES
1007: PetscShellInitializePackage(PETSC_NULL);
1008: #endif
1010: PetscHeaderCreate(shell_,_p_PetscShell,PetscInt,PETSC_SHELL_CLASSID,0,"PetscShell","String message interpreter and dependence organizer","shell",comm,PetscShellDestroy,PetscShellView);
1011: shell_->visitor = PETSC_NULL;
1012: shell_->component = PETSC_NULL;
1013: shell_->vtable_type = PETSC_SHELL_VTABLE_NONE;
1014: shell_->vtable = PETSC_NULL;
1015: shell_->N = shell_->maxN = 0;
1016: /* FIX: should only create a graph on demand */
1017: PetscShellGraphCreate(&shell_->dep_graph);
1018: PetscObjectChangeTypeName((PetscObject)shell_,PETSCSHELL);
1019: *shell = shell_;
1020: return(0);
1021: }/* PetscShellCreate() */
1024: #undef __FUNCT__
1026: /*@C
1027: PetscShellGetComponent -- extract shell's component corresponding to key.
1028: If key has been previously used with PetscShellRegisterComponentShell(),
1029: PetscShellRegisterComponentURL() or PetscShellRegisterDependence()
1030: this will return the corresponding component created during the first
1031: such call.
1033: Logically collective on comm.
1035: Input paramters:
1036: + shell -- PetscShell object being queried
1037: - key -- a character string designating the key of the component being sought
1039: Output parameters:
1040: + component -- the extracted component PetscShell object (or PETSC_NULL)
1041: - found -- PetscBool flag indicating whether a component with the given key has been found (or PETSC_NULL)
1043: Notes: component can be PETSC_NULL, in which case only found is returned (if it is itself not PETSC_NULL).
1044: This is useful for quering for the presence of the given component, without extracting it.
1046: Level: beginner.
1048: .seealso: PetscShellRegisterComponentShell(), PetscShellRegisterComponentURL(), PetscShellRegisterDependence()
1049: @*/
1050: PetscErrorCode PetscShellGetComponent(PetscShell shell, const char key[], PetscShell *component, PetscBool *found) {
1051: PetscInt id;
1053: PetscBool found_;
1057: PetscShellGetKeyID_Private(shell, key, &id, &found_);
1058: if(found_ && component) {
1059: *component = shell->component[id];
1060: }
1061: if(found) {*found = found_;}
1062: return(0);
1063: }/* PetscShellGetComponent() */
1067: #undef __FUNCT__
1069: PetscErrorCode PetscShellFinalizePackage(void)
1070: {
1072: PetscShellPackageInitialized = PETSC_FALSE;
1073: return(0);
1074: }/* PetscShellFinalizePackage() */
1077: #undef __FUNCT__
1079: PetscErrorCode PetscShellInitializePackage(const char path[]){
1082: if(PetscShellPackageInitialized) return(0);
1083: PetscShellPackageInitialized = PETSC_TRUE;
1084: /* Register classes */
1085: PetscClassIdRegister(PETSC_SHELL_CLASS_NAME, &PETSC_SHELL_CLASSID);
1086: /* Register finalization routine */
1087: PetscRegisterFinalize(PetscShellFinalizePackage);
1088: return(0);
1089: }/* PetscShellInitializePackage() */
1091: /* ---------------------------------------------------------------------*/
1092: /*
1093: The variable Petsc_Shell_default_keyval is used to indicate an MPI attribute that
1094: is attached to a communicator, in this case the attribute is a PetscShell.
1095: */
1096: static PetscMPIInt Petsc_Shell_default_keyval = MPI_KEYVAL_INVALID;
1098: #undef __FUNCT__
1100: PetscShell PETSC_SHELL_DEFAULT_(MPI_Comm comm) {
1102: PetscBool flg;
1103: PetscShell shell;
1106: if (Petsc_Shell_default_keyval == MPI_KEYVAL_INVALID) {
1107: MPI_Keyval_create(MPI_NULL_COPY_FN,MPI_NULL_DELETE_FN,&Petsc_Shell_default_keyval,0);
1108: if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_SHELL_DEFAULT_",__FILE__,__SDIR__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," "); return(0);}
1109: }
1110: MPI_Attr_get(comm,Petsc_Shell_default_keyval,(void **)(&shell),(PetscMPIInt*)&flg);
1111: if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_SHELL_DEFAULT_",__FILE__,__SDIR__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," "); return(0);}
1112: if (!flg) { /* PetscShell not yet created */
1113: PetscShellCreate(comm, &shell);
1114: if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_SHELL_DEFAULT_",__FILE__,__SDIR__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," "); return(0);}
1115: PetscObjectRegisterDestroy((PetscObject)shell);
1116: if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_SHELL_DEFAULT_",__FILE__,__SDIR__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," "); return(0);}
1117: MPI_Attr_put(comm,Petsc_Shell_default_keyval,(void*)shell);
1118: if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_SHELL_DEFAULT_",__FILE__,__SDIR__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," "); return(0);}
1119: }
1120: PetscFunctionReturn(shell);
1121: }/* PETSC_SHELL_DEFAULT_() */