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_() */