Actual source code: fwk.c

  2: #include <petscsys.h>
  3: #include <petscfwk.h>

  5: /* FIX: is it okay to include this directly? */
  6: #include <ctype.h>

  8:  PetscClassId PETSC_FWK_CLASSID;
  9: static char PETSC_FWK_CLASS_NAME[] = "PetscFwk";
 10: static PetscBool  PetscFwkPackageInitialized = PETSC_FALSE;


 13: typedef PetscErrorCode (*PetscFwkPythonLoadVTableFunction)(PetscFwk fwk, const char* path, const char* name, void **vtable);
 14: typedef PetscErrorCode (*PetscFwkPythonClearVTableFunction)(PetscFwk fwk, void **vtable);
 15: typedef PetscErrorCode (*PetscFwkPythonCallFunction)(PetscFwk fwk, const char* message, void *vtable);

 18: PetscFwkPythonLoadVTableFunction      PetscFwkPythonLoadVTable      = PETSC_NULL;
 19: PetscFwkPythonClearVTableFunction     PetscFwkPythonClearVTable     = PETSC_NULL;
 20: PetscFwkPythonCallFunction            PetscFwkPythonCall            = PETSC_NULL;

 23: #define PETSC_FWK_CHECKINIT_PYTHON()                                        \
 24:   if(PetscFwkPythonLoadVTable == PETSC_NULL) {                                \
 26:     PetscPythonInitialize(PETSC_NULL,PETSC_NULL);        \
 27:     if(PetscFwkPythonLoadVTable == PETSC_NULL) {                                \
 28:       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,                                \
 29:               "Couldn't initialize Python support for PetscFwk");        \
 30:     }                                                                        \
 31:   }                                                                        
 32: 
 33: #define PETSC_FWK_LOAD_VTABLE_PYTHON(fwk, path, name)                   \
 34:   PETSC_FWK_CHECKINIT_PYTHON();                                                \
 35:   {                                                                        \
 37:     PetscFwkPythonLoadVTable(fwk, path, name, &(fwk->vtable));   \
 38:     if (ierr) { PetscPythonPrintError(); SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB, "Python error"); } \
 39:   }

 41: #define PETSC_FWK_CLEAR_VTABLE_PYTHON(fwk)                              \
 42:   PETSC_FWK_CHECKINIT_PYTHON();                                                \
 43:   {                                                                        \
 45:     PetscFwkPythonClearVTable(fwk, &(fwk->vtable));              \
 46:     if (ierr) { PetscPythonPrintError(); SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB, "Python error"); } \
 47:   }
 48: 
 49: #define PETSC_FWK_CALL_PYTHON(fwk, message)                             \
 50:   PETSC_FWK_CHECKINIT_PYTHON();                                         \
 51:   {                                                                        \
 53:     PetscFwkPythonCall(fwk, message, fwk->vtable);                           \
 54:     if (ierr) { PetscPythonPrintError(); SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB, "Python error"); } \
 55:   }
 56: 

 58: /* ---------------------------------------------------------------------------------------------- */
 59: struct _n_PetscFwkGraph {
 60:   PetscInt vcount, vmax; /* actual and allocated number of vertices */
 61:   PetscInt *i, *j, *outdegree; /* (A)IJ structure for the underlying matrix: 
 62:                                   i[row]             the row offset into j, 
 63:                                   i[row+1] - i[row]  allocated number of entries for row,
 64:                                   outdegree[row]     actual number of entries in row
 65:                                */
 66:   PetscInt *indegree;
 67:   PetscInt nz, maxnz;
 68:   PetscInt rowreallocs, colreallocs;
 69: };

 71: typedef struct _n_PetscFwkGraph *PetscFwkGraph;

 73: #define CHUNKSIZE 5
 74: /*
 75:     Inserts the (row,col) entry, allocating larger arrays, if necessary. 
 76:     Does NOT check whether row and col are within range (< graph->vcount).
 77:     Does NOT check whether the entry is already present.
 78: */
 79: #undef  __FUNCT__
 81: PetscErrorCode PetscFwkGraphExpandRow_Private(PetscFwkGraph graph, PetscInt row)
 82: {
 84:   PetscInt       rowlen, rowmax, rowoffset;
 85:   PetscInt       ii;

 88:   rowlen = graph->outdegree[row];
 89:   rowmax = graph->i[row+1] - graph->i[row];
 90:   rowoffset = graph->i[row];
 91:   if (rowlen >= rowmax) {
 92:     /* there is no extra room in row, therefore enlarge */
 93:     PetscInt   new_nz = graph->i[graph->vcount] + CHUNKSIZE;
 94:     PetscInt   *new_i=0,*new_j=0;
 95: 
 96:     /* malloc new storage space */
 97:     PetscMalloc(new_nz*sizeof(PetscInt),&new_j);
 98:     PetscMalloc((graph->vmax+1)*sizeof(PetscInt),&new_i);
 99: 
100:     /* copy over old data into new slots */
101:     for (ii=0; ii<row+1; ii++) {new_i[ii] = graph->i[ii];}
102:     for (ii=row+1; ii<graph->vmax+1; ii++) {new_i[ii] = graph->i[ii]+CHUNKSIZE;}
103:     PetscMemcpy(new_j,graph->j,(rowoffset+rowlen)*sizeof(PetscInt));
104:     PetscMemcpy(new_j+rowoffset+rowlen+CHUNKSIZE,graph->j+rowoffset+rowlen,(new_nz - CHUNKSIZE - rowoffset - rowlen)*sizeof(PetscInt));
105:     /* free up old matrix storage */
106:     PetscFree(graph->j);
107:     PetscFree(graph->i);
108:     graph->i = new_i; graph->j = new_j;
109:     graph->maxnz     += CHUNKSIZE;
110:     graph->colreallocs++;
111:   }
112:   return(0);
113: }/* PetscFwkGraphExpandRow_Private() */

115: #undef  __FUNCT__
117: PetscErrorCode PetscFwkGraphAddVertex(PetscFwkGraph graph, PetscInt *v) {
118:   PetscInt ii;
121:   if(graph->vcount >= graph->vmax) {
122:     /* Add rows */
123:     PetscInt   *new_i=0, *new_outdegree=0, *new_indegree;
124: 
125:     /* malloc new storage space */
126:     PetscMalloc((graph->vmax+CHUNKSIZE+1)*sizeof(PetscInt),&new_i);
127:     PetscMalloc((graph->vmax+CHUNKSIZE)*sizeof(PetscInt),&new_outdegree);
128:     PetscMalloc((graph->vmax+CHUNKSIZE)*sizeof(PetscInt),&new_indegree);
129:     PetscMemzero(new_outdegree, (graph->vmax+CHUNKSIZE)*sizeof(PetscInt));
130:     PetscMemzero(new_indegree, (graph->vmax+CHUNKSIZE)*sizeof(PetscInt));


133:     /* copy over old data into new slots */
134:     PetscMemcpy(new_i,graph->i,(graph->vmax+1)*sizeof(PetscInt));
135:     PetscMemcpy(new_outdegree,graph->outdegree,(graph->vmax)*sizeof(PetscInt));
136:     PetscMemcpy(new_indegree,graph->indegree,(graph->vmax)*sizeof(PetscInt));
137:     for (ii=graph->vmax+1; ii<=graph->vmax+CHUNKSIZE; ++ii) {
138:       new_i[ii] = graph->i[graph->vmax];
139:     }

141:     /* free up old matrix storage */
142:     PetscFree(graph->i);
143:     PetscFree(graph->outdegree);
144:     PetscFree(graph->indegree);
145:     graph->i = new_i; graph->outdegree = new_outdegree; graph->indegree = new_indegree;
146: 
147:     graph->vmax += CHUNKSIZE;
148:     graph->rowreallocs++;
149:   }
150:   if(v) {*v = graph->vcount;}
151:   ++(graph->vcount);
152:   return(0);
153: }/* PetscFwkGraphAddVertex() */

155: #undef  __FUNCT__
157: PetscErrorCode PetscFwkGraphAddEdge(PetscFwkGraph graph, PetscInt row, PetscInt col) {
158:   PetscErrorCode        ierr;
159:   PetscInt              *rp,low,high,t,ii,i;

162:   if(row < 0 || row >= graph->vcount) {
163:     SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Source vertex %D out of range: min %D max %D",row, 0, graph->vcount);
164:   }
165:   if(col < 0 || col >= graph->vcount) {
166:     SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Target vertex %D out of range: min %D max %D",col, 0, graph->vcount);
167:   }
168:   rp   = graph->j + graph->i[row];
169:   low  = 0;
170:   high = graph->outdegree[row];
171:   while (high-low > 5) {
172:     t = (low+high)/2;
173:     if (rp[t] > col) high = t;
174:     else             low  = t;
175:   }
176:   for (i=low; i<high; ++i) {
177:     if (rp[i] > col) break;
178:     if (rp[i] == col) {
179:       goto we_are_done;
180:     }
181:   }
182:   PetscFwkGraphExpandRow_Private(graph, row);
183:   /* 
184:      If the graph was empty before, graph->j was NULL and rp was NULL as well.  
185:      Now that the row has been expanded, rp needs to be reset. 
186:   */
187:   rp = graph->j + graph->i[row];
188:   /* shift up all the later entries in this row */
189:   for (ii=graph->outdegree[row]; ii>=i; --ii) {
190:     rp[ii+1] = rp[ii];
191:   }
192:   rp[i] = col;
193:   ++(graph->outdegree[row]);
194:   ++(graph->indegree[col]);
195:   ++(graph->nz);
196: 
197:  we_are_done:
198:   return(0);
199: }/* PetscFwkGraphAddEdge() */


202: #undef  __FUNCT__
204: PetscErrorCode PetscFwkGraphTopologicalSort(PetscFwkGraph graph, PetscInt *n, PetscInt **queue) {
205:   PetscBool  *queued;
206:   PetscInt   *indegree;
207:   PetscInt ii, k, jj, Nqueued = 0;
208:   PetscBool  progress;
211:   if(!n || !queue) {
212:     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG, "Invalid return argument pointers n or vertices");
213:   }
214:   *n = graph->vcount;
215:   PetscMalloc(sizeof(PetscInt)*graph->vcount, queue);
216:   PetscMalloc(sizeof(PetscBool)*graph->vcount, &queued);
217:   PetscMalloc(sizeof(PetscInt)*graph->vcount, &indegree);
218:   for(ii = 0; ii < graph->vcount; ++ii) {
219:     queued[ii]   = PETSC_FALSE;
220:     indegree[ii] = graph->indegree[ii];
221:   }
222:   while(Nqueued < graph->vcount) {
223:     progress = PETSC_FALSE;
224:     for(ii = 0; ii < graph->vcount; ++ii) {
225:       /* If ii is not queued yet, and the indegree is 0, queue it. */
226:       if(!queued[ii] && !indegree[ii]) {
227:         (*queue)[Nqueued] = ii;
228:         queued[ii] = PETSC_TRUE;
229:         ++Nqueued;
230:         progress = PETSC_TRUE;
231:         /* Reduce the indegree of all vertices in row ii */
232:         for(k = 0; k < graph->outdegree[ii]; ++k) {
233:           jj = graph->j[graph->i[ii]+k];
234:           --(indegree[jj]);
235:           /* 
236:              It probably would be more efficient to make a recursive call to the body of the for loop 
237:              with the jj in place of ii, but we use a simple-minded algorithm instead, since the graphs
238:              we anticipate encountering are tiny. 
239:           */
240:         }/* for(k) */
241:       }/* if(!queued) */
242:     }/* for(ii) */
243:     /* If no progress was made during this iteration, the graph must have a cycle */
244:     if(!progress) {
245:       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE, "Cycle detected in the dependency graph");
246:     }
247:   }/* while(Nqueued) */
248:   PetscFree(queued);
249:   PetscFree(indegree);
250:   return(0);
251: }/* PetscFwkGraphTopologicalSort() */

253: #undef  __FUNCT__
255: PetscErrorCode PetscFwkGraphDestroy(PetscFwkGraph graph)
256: {
259:   PetscFree(graph->i);
260:   PetscFree(graph->j);
261:   PetscFree(graph->outdegree);
262:   PetscFree(graph->indegree);
263:   PetscFree(graph);
264:   return(0);
265: }/* PetscFwkGraphDestroy() */

267: #undef  __FUNCT__
269: PetscErrorCode PetscFwkGraphCreate(PetscFwkGraph *graph_p)
270: {
271:   PetscFwkGraph graph;
274:   PetscNew(struct _n_PetscFwkGraph, graph_p);
275:   graph = *graph_p;
276:   graph->vcount = graph->vmax = graph->nz = graph->maxnz = graph->rowreallocs = graph->colreallocs = 0;
277:   PetscMalloc(sizeof(PetscInt), &(graph->i));
278:   graph->j = graph->outdegree = graph->indegree = PETSC_NULL;
279:   return(0);
280: }/* PetscFwkGraphCreate() */



284: /* ------------------------------------------------------------------------------------------------------- */

286: typedef enum{PETSC_FWK_VTABLE_NONE, PETSC_FWK_VTABLE_SO, PETSC_FWK_VTABLE_PY} PetscFwkVTableType;

288: struct _n_PetscFwkVTable_SO {
289:   char           *path, *name;
290: };


293: struct _p_PetscFwk {
294:   PETSCHEADER(int);
295:   PetscFwkVTableType        vtable_type;
296:   void                      *vtable;
297:   char *                    url;
298:   PetscFwk                  parent;
299:   PetscInt                  N, maxN;
300:   PetscFwk                  *component;
301:   PetscFwkGraph             dep_graph;
302: };

304: static PetscFwk defaultFwk = PETSC_NULL;



308: /* ------------------------------------------------------------------------------------------------------- */

310: typedef PetscErrorCode (*PetscFwkCallFunction)(PetscFwk, const char*);
311: typedef PetscErrorCode (*PetscFwkMessageFunction)(PetscFwk);
312: typedef void (*QueryFunction)(void);

314: static PetscDLLibrary PetscFwkDLLibrariesLoaded = 0;

316: #undef  __FUNCT__
318: PetscErrorCode PetscFwkCall_SO(PetscFwk fwk, const char* path, const char* name, const char* message) {
319:   size_t    namelen, messagelen, msgfunclen, callfunclen;
320:   char *msgfunc  = PETSC_NULL, *callfunc = PETSC_NULL;
321:   PetscFwkCallFunction call = PETSC_NULL;
322:   PetscFwkMessageFunction msg = PETSC_NULL;
325:   PetscStrlen(name, &namelen);
326:   PetscStrlen(message, &messagelen);
327:   msgfunclen = namelen + messagelen;
328:   PetscMalloc(sizeof(char)*(msgfunclen+1), &msgfunc);
329:   msgfunc[0] = '\0';
330:   if(namelen){
331:     PetscStrcat(msgfunc, name);
332:   }
333:   PetscStrcat(msgfunc, message);
334:   if(namelen) {
335:     /* HACK: is 'toupper' part of the C standard? Looks like starting with C89. */
336:     msgfunc[namelen] = toupper(msgfunc[namelen]);
337:   }
338:   PetscDLLibrarySym(((PetscObject)fwk)->comm, &PetscFwkDLLibrariesLoaded, path, msgfunc, (void **)(&msg));
339:   PetscFree(msgfunc);
340:   if(msg) {
341:     (*msg)(fwk);
342:     return(0);
343:   }
344:   callfunclen        = namelen+4;
345:   PetscMalloc(sizeof(char)*(callfunclen+1), &callfunc);
346:   if(namelen) {
347:     PetscStrcpy(callfunc, name);
348:   }
349:   if(namelen){
350:     PetscStrcat(callfunc, "Call");
351:   }
352:   else {
353:     PetscStrcat(callfunc, "call");
354:   }
355:   PetscDLLibrarySym(((PetscObject)fwk)->comm, &PetscFwkDLLibrariesLoaded, path, callfunc, (void**)(&call));
356:   PetscFree(callfunc);
357:   if(call) {
358:     (*call)(fwk, message);
359:     return(0);
360:   }
361:   SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "PetscFwk '%s' cannot execute '%s'", ((PetscObject)fwk)->name, message);
362:   return(0);
363: }/* PetscFwkCall_SO() */


366: #undef  __FUNCT__
368: PetscErrorCode PetscFwkCall_NONE(PetscFwk fwk, const char* message) {
369:   PetscFwkCallFunction call = PETSC_NULL;
370:   PetscFwkMessageFunction msg = PETSC_NULL;
373:   PetscFListFind(((PetscObject)fwk)->qlist, ((PetscObject)fwk)->comm, message,PETSC_FALSE, (QueryFunction*)(&msg));
374:   if(msg) {
375:     (*msg)(fwk);
376:     return(0);
377:   }
378:   PetscFListFind(((PetscObject)fwk)->qlist, ((PetscObject)fwk)->comm, "call",PETSC_FALSE, (QueryFunction*)(&call));
379:   if(call) {
380:     (*call)(fwk, message);
381:     return(0);
382:   }
383:   SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "PetscFwk '%s' cannot execute '%s'", ((PetscObject)fwk)->name, message);
384:   return(0);
385: }/* PetscFwkCall_NONE() */


388: #undef  __FUNCT__
390: /*@C 
391:    PetscFwkCall -- send a string message to a PetscFwk object.  

393:    Logically collective on PetscFwk.

395:    Input paramters:
396: +  fwk     -- a PetscFwk object
397: -  message -- a character string

399:    Notes: In response to the message the object performs actions defined by its URL (see PetscFwkSetURL()). 
400:           Side effects may include, in particular, actions on the composed objects (see PetscObjectCompose()).

402:   Level: beginner.

404: .seealso: PetscFwkSetURL(), PetscFwkGetURL(), PetscObjectCompose(), PetscObjectQuery()
405: @*/
406: PetscErrorCode PetscFwkCall(PetscFwk fwk, const char* message) {
411:   if(!message || !message[0]) {
412:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Null or empty message string");
413:   }
414:   switch(fwk->vtable_type) {
415:   case PETSC_FWK_VTABLE_NONE:
416:     PetscFwkCall_NONE(fwk, message);
417:     break;
418:   case PETSC_FWK_VTABLE_SO:
419:     PetscFwkCall_SO(fwk,
420:                            ((struct _n_PetscFwkVTable_SO*)fwk->vtable)->path,
421:                            ((struct _n_PetscFwkVTable_SO*)fwk->vtable)->name,
422:                            message);
423: 
424:     break;
425:   case PETSC_FWK_VTABLE_PY:
426:     PETSC_FWK_CALL_PYTHON(fwk, message);
427:     break;
428:   default:
429:     SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown PetscFwkVTableType value");
430:     break;
431:   }
432:   return(0);
433: }/* PetscFwkCall() */


436: #define PETSC_FWK_MAX_URL_LENGTH 1024
437: /* 
438:    Normalize the url (by truncating to PETSC_FWK_MAX_URL_LENGTH) and parse it to find out the component type and location.
439:    Warning: the returned char pointers are borrowed and their contents must be copied elsewhere to be preserved.
440: */
441: #undef  __FUNCT__
443: PetscErrorCode  PetscFwkParseURL_Private(const char inurl[], char **outpath, char **outname, PetscFwkVTableType *outtype){
444:   char *n, *s;
445:   static PetscInt nlen = PETSC_FWK_MAX_URL_LENGTH;
446:   static char path[PETSC_FWK_MAX_URL_LENGTH+1], name[PETSC_FWK_MAX_URL_LENGTH+1];
447:   PetscFwkVTableType type = PETSC_FWK_VTABLE_NONE;
450:   /* FIX: this routine should replace the filesystem path by an abolute path for real normalization */
451:   /* Copy the inurl so we can manipulate it inplace and also truncate to the max allowable length */
452:   PetscStrncpy(path, inurl, nlen);
453:   /* Split url <path>:<name> into <path> and <name> */
454:   PetscStrrchr(path,':',&n);
455:   /* Make sure it's not the ":/" of the "://" separator */
456:   if(!n[0] || n[0] == '/') {
457:     SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,
458:            "Could not locate component name within the URL.\n"
459:            "Must have url = [<path/><library>:]<name>.\n"
460:            "Instead got %s\n"
461:            "Remember that URL is always truncated to the max allowed length of %d",
462:            inurl, nlen);
463:   }
464:   /* Copy n to name */
465:   PetscStrcpy(name, n);
466:   /* If n isn't the whole path (i.e., there is a ':' separator), end 'path' right before the located ':' */
467:   if(n == path) {
468:     /* 
469:        No library is provided, so the component is assumed to be "local", that is
470:        defined in an already loaded executable. So we set type to .so, path to "",
471:        and look for the configure symbol among already loaded symbols 
472:        (or count on PetscDLXXX to do that.
473:     */
474:     type = PETSC_FWK_VTABLE_SO;
475:     path[0] = '\0';
476:   }
477:   else {
478:     n[-1] = '\0';
479:     /* Find the library suffix and determine the component library type: .so or .py */
480:     PetscStrrchr(path,'.',&s);
481:     /* FIX: we should really be using PETSc's internally defined suffices */
482:     if(s != path && s[-1] == '.') {
483:       if((s[0] == 'a' && s[1] == '\0') || (s[0] == 's' && s[1] == 'o' && s[2] == '\0')){
484:         type = PETSC_FWK_VTABLE_SO;
485:       }
486:       else if (s[0] == 'p' && s[1] == 'y' && s[2] == '\0'){
487:         type = PETSC_FWK_VTABLE_PY;
488:       }
489:       else {
490:         SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,
491:                  "Unknown library suffix within the URL.\n"
492:                  "Must have url = [<path/><library>:]<name>,\n"
493:                  "where library = <libname>.<suffix>, suffix = .a || .so || .py.\n"
494:                  "Instead got url %s\n"
495:                  "Remember that URL is always truncated to the max allowed length of %d",
496:                  inurl, s,nlen);
497:       }
498:     }
499:   }
500:   *outpath = path;
501:   *outname = name;
502:   *outtype = type;
503:   return(0);
504: }/* PetscFwkParseURL_Private() */

506: #undef  __FUNCT__
508: PetscErrorCode  PetscFwkClearURL_Private(PetscFwk fwk) {
511:   switch(fwk->vtable_type) {
512:   case PETSC_FWK_VTABLE_SO:
513:     {
514:       struct _n_PetscFwkVTable_SO *vt = (struct _n_PetscFwkVTable_SO*)(fwk->vtable);
515:       PetscFree(vt->path);
516:       PetscFree(vt->name);
517:       PetscFree(vt);
518:       fwk->vtable = PETSC_NULL;
519:       fwk->vtable_type = PETSC_FWK_VTABLE_NONE;
520:     }
521:     break;
522:   case PETSC_FWK_VTABLE_PY:
523:     PETSC_FWK_CLEAR_VTABLE_PYTHON(fwk);
524:     break;
525:   case PETSC_FWK_VTABLE_NONE:
526:     break;
527:   default:
528:     SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,
529:              "Unknown PetscFwk vtable type: %d", fwk->vtable_type);
530:   }
531:   PetscFree(fwk->url);
532:   fwk->url = PETSC_NULL;
533:   return(0);
534: }/* PetscFwkClearURL_Private() */

536: #undef  __FUNCT__
538: /*@C 
539:    PetscFwkSetURL -- set a backend implementing PetscFwk functionality from the URL string.

541:    Logically collective on PetscFwk.

543:    Input paramters:
544: +  fwk -- a PetscFwk object
545: -  url -- URL string

547:    Notes: URL can point to a backendn -- a .so file or a .py file.  
548:      The .so file must contain symbols for function 'void call(const char[])' or symbols 'void <msg>(void)'
549:    for any message <msg> that PetscFwk is expected to understand.  When PetscFwkCall() is invoked
550:    with <msg>, a symbol for 'void <msg>(void)' is sought and called, if found.  If not, a symbol for
551:    'void call(const char[])' is sought and called with <msg> as the argument. If neither symbol is found,
552:    an error occurs.
553:      The .py file must define a class that implements 'call(str)' or '<msg>()' methods, as above.
554:      If no URL has been set, fwk attempts to reponsd to the message using function '<msg>' (failing that,
555:    'call') retrieved from fwk using PetscObjectQueryFunction().  If neither '<msg>' nor 'call' have been
556:    previusly composed with fwk (see PetscObjectComposeFunction()), an error occurs.

558:    Level: intermediate.

560: .seealso: PetscFwkGetURL(), PetscObjectCompose(), PetscObjectQuery(), PetscObjectComposeFunction()
561: @*/
562: PetscErrorCode  PetscFwkSetURL(PetscFwk fwk, const char url[]) {
564:   char *path, *name;
568:   if(fwk->vtable) {
569:     PetscFwkClearURL_Private(fwk);
570:   }
571:   PetscStrallocpy(url,  &(fwk->url));
572:   PetscFwkParseURL_Private(url, &path, &name, &fwk->vtable_type);
573:   switch(fwk->vtable_type) {
574:   case PETSC_FWK_VTABLE_SO:
575:     {
576:       struct _n_PetscFwkVTable_SO *vt;
577:       PetscMalloc(sizeof(struct _n_PetscFwkVTable_SO), &(vt));
578:       fwk->vtable = (void*)vt;
579:       PetscStrallocpy(path, &vt->path);
580:       PetscStrallocpy(name, &vt->name);
581:     }
582:     break;
583:   case PETSC_FWK_VTABLE_PY:
584:     PETSC_FWK_LOAD_VTABLE_PYTHON(fwk, path, name);
585:     break;
586:   default:
587:     SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,
588:              "Unknown PetscFwk vtable type: %d", fwk->vtable_type);
589:   }
590:   return(0);
591: }/* PetscFwkSetURL() */


594: #undef  __FUNCT__
596: /*@C 
597:    PetscFwkGetURL -- retrieve the URL defining the backend that implements the PetscFwkCall() functionality.

599:    Not collective.

601:    Input paramters:
602: .  fwk -- a PetscFwk object

604:    Output parameters:
605: .  url -- the URL string

607:    Level: beginner.

609: .seealso: PetscFwkSetURL(), PetscFwkCall()
610: @*/
611: PetscErrorCode  PetscFwkGetURL(PetscFwk fwk, const char **url) {
615:   *url = fwk->url;
616:   return(0);
617: }/* PetscFwkGetURL() */
618: 

620: /* ------------------------------------------------------------------------------------------------------- */
621: #undef  __FUNCT__
623: PetscErrorCode PetscFwkView(PetscFwk fwk, PetscViewer viewer) {
624:   PetscInt *vertices, N;
625:   PetscInt i, id;
626:   PetscBool         iascii;
627:   PetscErrorCode    ierr;
630:   if (!viewer) {
631:     PetscViewerASCIIGetStdout(((PetscObject)fwk)->comm,&viewer);
632:   }
635:   PetscTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);
636:   if (iascii) {
637:     PetscViewerASCIIPrintf(viewer, "Framework url: %s\n", fwk->url);
638:     PetscViewerASCIIPrintf(viewer, "Components are visited in this order:\n");
639:     PetscFwkGraphTopologicalSort(fwk->dep_graph, &N, &vertices);
640:     for(i = 0; i < N; ++i) {
641:       if(i) {
642:         PetscViewerASCIIPrintf(viewer, "\n");
643:       }
644:       id = vertices[i];
645:       PetscViewerASCIIPrintf(viewer, "%d: name:%s, url:%s", id, ((PetscObject)(fwk->component[id]))->name, fwk->component[id]->url);
646:     }
647:     PetscViewerASCIIPrintf(viewer, "\n");
648:     PetscFree(vertices);
649:   }
650:   else {
651:     SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG, "PetscFwk can only be viewed with an ASCII viewer");
652:   }
653:   return(0);
654: }/* PetscFwkView() */

656: #undef  __FUNCT__
658: PetscErrorCode PetscFwkGetParent(PetscFwk fwk, PetscFwk *parent)
659: {
663:   *parent = fwk->parent;
664:   return(0);
665: }/* PetscFwkGetParent() */

667: #undef  __FUNCT__
669: PetscErrorCode PetscFwkVisit(PetscFwk fwk, const char* message){
670:   PetscInt i, id, N, *vertices;
671:   PetscFwk component;
676:   PetscFwkGraphTopologicalSort(fwk->dep_graph, &N, &vertices);
677:   for(i = 0; i < N; ++i) {
678:     id = vertices[i];
679:     component = fwk->component[id];
680:     /* Save the component's visitor */
681:     component->parent = fwk;
682:     /* Call "configure" */
683:     PetscFwkCall(component, message);
684:     /* Clear visitor */
685:     component->parent = PETSC_NULL;
686:   }
687:   PetscFree(vertices);
688:   return(0);
689: }/* PetscFwkVisit() */

691: #undef  __FUNCT__
693: PetscErrorCode  PetscFwkGetKeyID_Private(PetscFwk fwk, const char key[], PetscInt *_id, PetscBool  *_found){
694:   PetscInt i;
695:   PetscBool  eq;
698:   /* Check whether a component with the given key has already been registered. */
699:   if(_found){*_found = PETSC_FALSE;}
700:   for(i = 0; i < fwk->N; ++i) {
701:     PetscStrcmp(key, ((PetscObject)fwk->component[i])->name, &eq);
702:     if(eq) {
703:       if(_id) {*_id = i;}
704:       if(_found){*_found = PETSC_TRUE;}
705:     }
706:   }
707:   return(0);
708: }/* PetscFwkGetKeyID_Private() */

710: #undef  __FUNCT__
712: PetscErrorCode  PetscFwkRegisterKey_Private(PetscFwk fwk, const char key[], PetscInt *_id) {
713:   PetscInt v, id;
714:   PetscBool  found;
717:   /* Check whether a component with the given url has already been registered.  If so, return its id, if it has been requested. */
718:   PetscFwkGetKeyID_Private(fwk, key, &id, &found);
719:   if(found) {
720:     goto alldone;
721:   }
722:   /***/
723:   /* No such key found. */
724:   /* Create a new component for this key. */
725:   if(fwk->N >= fwk->maxN) {
726:     /* No more empty component slots, therefore, expand the component array */
727:     PetscFwk *new_components;
728:     PetscMalloc(sizeof(PetscFwk)*(fwk->maxN+CHUNKSIZE), &new_components);
729:     PetscMemcpy(new_components, fwk->component, sizeof(PetscFwk)*(fwk->maxN));
730:     PetscMemzero(new_components+fwk->maxN,sizeof(PetscFwk)*(CHUNKSIZE));
731:     PetscFree(fwk->component);
732:     fwk->component = new_components;
733:     fwk->maxN += CHUNKSIZE;
734:   }
735:   id = fwk->N;
736:   ++(fwk->N);
737:   /* Store key */
738:   /* Create the corresponding component. */
739:   PetscFwkCreate(((PetscObject)fwk)->comm, fwk->component+id);
740:   PetscObjectSetName((PetscObject)fwk->component[id], key);
741:   /* Add a new vertex to the dependence graph.  This vertex will correspond to the newly registered component. */
742:   PetscFwkGraphAddVertex(fwk->dep_graph, &v);
743:   /* v must equal id */
744:   if(v != id) {
745:     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);
746:   }
747:  alldone:
748:   if(_id) {
749:     *_id = id;
750:   }
751:   return(0);
752: }/* PetscFwkRegisterKey_Private() */


755: #undef  __FUNCT__
757: PetscErrorCode  PetscFwkRegisterComponent(PetscFwk fwk, const char key[]){
762:   PetscFwkRegisterKey_Private(fwk, key, PETSC_NULL);
763:   return(0);
764: }/* PetscFwkRegisterComponent() */

766: #undef  __FUNCT__
768: PetscErrorCode  PetscFwkRegisterComponentURL(PetscFwk fwk, const char key[], const char url[]){
770:   PetscInt id;
775:   PetscFwkRegisterKey_Private(fwk, key, &id);
776:   PetscFwkSetURL(fwk->component[id], url);
777:   return(0);
778: }/* PetscFwkRegisterComponentURL() */


781: #undef  __FUNCT__
783: PetscErrorCode  PetscFwkRegisterDependence(PetscFwk fwk, const char clientkey[], const char serverkey[])
784: {
785:   PetscInt clientid, serverid;
791:   /* Register keys */
792:   PetscFwkRegisterKey_Private(fwk, clientkey, &clientid);
793:   PetscFwkRegisterKey_Private(fwk, serverkey, &serverid);
794:   /*
795:     Add the dependency edge to the dependence_graph as follows (serverurl, clienturl): 
796:      this means "server preceeds client", so server should be configured first.
797:   */
798:   PetscFwkGraphAddEdge(fwk->dep_graph, clientid, serverid);
799:   return(0);
800: }/* PetscFwkRegisterDependence() */



804: #undef  __FUNCT__
806: /*@C 
807:    PetscFwkDestroy -- destroy PetscFwk.

809:    Not collective.

811:    Input paramters:
812: .  fwk -- a PetscFwk object

814:    Level: beginner.

816: .seealso: PetscFwkCreate(), PetscFwkSetURL(), PetscFwkCall()
817: @*/
818: PetscErrorCode  PetscFwkDestroy(PetscFwk *fwk)
819: {
820:   PetscInt       i;
822: 
824:   if (!*fwk) return(0);
826:   if (--((PetscObject)(*fwk))->refct > 0) return(0);
827:   for(i = 0; i < (*fwk)->N; ++i){
828:     PetscObjectDestroy((PetscObject*)&(*fwk)->component[i]);
829:   }
830:   PetscFree((*fwk)->component);
831:   PetscFwkGraphDestroy((*fwk)->dep_graph);
832:   PetscHeaderDestroy(fwk);
833:   return(0);
834: }/* PetscFwkDestroy()*/

836: #undef  __FUNCT__
838: /*@C 
839:    PetscFwkCreate -- create an empty PetscFwk object.

841:    Logically collective on comm.

843:    Input paramters:
844: .  comm      -- the MPI_Comm to create the PetscFwk object on.

846:    Output parameters:
847: .  framework -- the created PetscFwk object.

849:    Level: beginner.

851: .seealso: PetscFwkDestroy(), PetscFwkSetURL(), PetscFwkCall()
852: @*/
853: PetscErrorCode  PetscFwkCreate(MPI_Comm comm, PetscFwk *framework){
854:   PetscFwk fwk;
857: #ifndef PETSC_USE_DYNAMIC_LIBRARIES
858:   PetscFwkInitializePackage(PETSC_NULL);
859: #endif
861:   PetscHeaderCreate(fwk,_p_PetscFwk,PetscInt,PETSC_FWK_CLASSID,0,"PetscFwk","Object dependence Framework","fwk",comm,PetscFwkDestroy,PetscFwkView);
862:   fwk->parent      = PETSC_NULL;
863:   fwk->component   = PETSC_NULL;
864:   fwk->vtable_type = PETSC_FWK_VTABLE_NONE;
865:   fwk->vtable      = PETSC_NULL;
866:   fwk->N = fwk->maxN = 0;
867:   /* FIX: should only create a graph on demand */
868:   PetscFwkGraphCreate(&fwk->dep_graph);
869:   PetscObjectChangeTypeName((PetscObject)fwk,PETSCFWK);
870:   *framework = fwk;
871:   return(0);
872: }/* PetscFwkCreate() */


875: #undef  __FUNCT__
877: PetscErrorCode  PetscFwkGetComponent(PetscFwk fwk, const char key[], PetscFwk *_component, PetscBool  *_found) {
878:   PetscInt id;
879:   PetscBool  found;
886:   PetscFwkGetKeyID_Private(fwk, key, &id, &found);
887:   if(found && _component) {
888:     *_component = fwk->component[id];
889:   }
890:   if(_found) {*_found = found;}
891:   return(0);
892: }/* PetscFwkGetComponent() */



896: #undef  __FUNCT__
898: PetscErrorCode PetscFwkFinalizePackage(void)
899: {
902:   if (defaultFwk) {
903:     PetscFwkDestroy(&defaultFwk);
904:   }
905:   PetscFwkPackageInitialized = PETSC_FALSE;
906:   return(0);
907: }/* PetscFwkFinalizePackage() */


910: #undef  __FUNCT__
912: PetscErrorCode PetscFwkInitializePackage(const char path[]){
915:   if(PetscFwkPackageInitialized) return(0);
916:   PetscFwkPackageInitialized = PETSC_TRUE;
917:   /* Register classes */
918:   PetscClassIdRegister(PETSC_FWK_CLASS_NAME, &PETSC_FWK_CLASSID);
919:   /* Register finalization routine */
920:   PetscRegisterFinalize(PetscFwkFinalizePackage);
921:   return(0);
922: }/* PetscFwkInitializePackage() */

924: /* ---------------------------------------------------------------------*/
925: /*
926:     The variable Petsc_Fwk_default_keyval is used to indicate an MPI attribute that
927:   is attached to a communicator, in this case the attribute is a PetscFwk.
928: */
929: static PetscMPIInt Petsc_Fwk_default_keyval = MPI_KEYVAL_INVALID;

931: #undef  __FUNCT__
933: PetscFwk  PETSC_FWK_DEFAULT_(MPI_Comm comm) {
935:   PetscBool      flg;
936:   PetscFwk       fwk;

939:   if (Petsc_Fwk_default_keyval == MPI_KEYVAL_INVALID) {
940:     MPI_Keyval_create(MPI_NULL_COPY_FN,MPI_NULL_DELETE_FN,&Petsc_Fwk_default_keyval,0);
941:     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_FWK_DEFAULT_",__FILE__,__SDIR__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," "); return(0);}
942:   }
943:   MPI_Attr_get(comm,Petsc_Fwk_default_keyval,(void **)(&fwk),(PetscMPIInt*)&flg);
944:   if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_FWK_DEFAULT_",__FILE__,__SDIR__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," "); return(0);}
945:   if (!flg) { /* PetscFwk not yet created */
946:     PetscFwkCreate(comm, &fwk);
947:     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_FWK_DEFAULT_",__FILE__,__SDIR__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," "); return(0);}
948:     PetscObjectRegisterDestroy((PetscObject)fwk);
949:     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_FWK_DEFAULT_",__FILE__,__SDIR__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," "); return(0);}
950:     MPI_Attr_put(comm,Petsc_Fwk_default_keyval,(void*)fwk);
951:     if (ierr) {PetscError(PETSC_COMM_SELF,__LINE__,"PETSC_FWK_DEFAULT_",__FILE__,__SDIR__,PETSC_ERR_PLIB,PETSC_ERROR_INITIAL," "); return(0);}
952:   }
953:   PetscFunctionReturn(fwk);
954: }/* PETSC_FWK_DEFAULT_() */