Actual source code: fwk.c
1: #define PETSC_DLL
3: #include petscsys.h
4: #include petscfwk.h
6: PetscCookie PETSC_FWK_COOKIE;
7: static char PETSC_FWK_CLASS_NAME[] = "PetscFwk";
9: static PetscTruth PetscFwkPackageInitialized = PETSC_FALSE;
12: /*
13: Graph/topological sort stuff from BOOST.
14: May need to be replaced with a custom, all-C implementation
15: */
16: // >> C++
17: #include <iostream>
18: #include <map>
19: #include <vector>
20: #include <list>
22: #include <boost/graph/graph_traits.hpp>
23: #include <boost/graph/adjacency_list.hpp>
24: #include <boost/graph/topological_sort.hpp>
27: struct vertex_id {
28: PetscInt id;
29: };
30: //
31: // We use bundled properties to store id with the vertex.
32: typedef ::boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS, vertex_id> dependence_graph_type;
33: typedef boost::graph_traits<dependence_graph_type>::vertex_descriptor vertex_type;
34: //
35: struct dependence_graph_cycle_detector_type : public boost::default_dfs_visitor {
36: void back_edge(boost::graph_traits<dependence_graph_type>::edge_descriptor e, const dependence_graph_type& g) {
37: std::basic_ostringstream<char> ss;
38: ss << "Edge creates dependence loop: [" << (g[::boost::source(e,g)].id) << " --> " << (g[::boost::target(e,g)].id) << "]; ";
39: throw ss.str();
40: }//back_edge()
41: };// dependence_graph_cycle_detector_type
42: // << C++
44: struct _p_PetscFwk {
45: PETSCHEADER(int);
46: // >> C++
47: // Since PetscFwk is allocated using the C-style PetscMalloc, the C++-object data members have to be 'newed', hance must be pointers
48: std::map<std::string, PetscInt> *id;
49: std::vector<std::string> *url;
50: std::vector<PetscFwkComponentConfigure> *configure;
51: std::vector<PetscObject> *component;
52: std::vector<vertex_type> *vertex;
53: dependence_graph_type *dependence_graph;
54: // << C++
55: };
57: // >> C++
58: #undef __FUNCT__
60: PetscErrorCode PetscFwkConfigure_Sort(PetscFwk fwk, std::list<vertex_type>& antitopological_vertex_order){
62: // >> C++
63: /* Run a cycle detector on the dependence graph */
64: try {
65: dependence_graph_cycle_detector_type cycle_detector;
66: ::boost::depth_first_search(*(fwk->dependence_graph), boost::visitor(cycle_detector));
67: }
68: catch(const std::string& s) {
69: SETERRQ1(PETSC_ERR_ARG_WRONGSTATE, "Component dependence graph has a loop: %s", s.c_str());
70: }
71: catch(...) {
72: SETERRQ(PETSC_ERR_ARG_WRONGSTATE, "Exception caught while detecting loops in the dependence graph");
73: }
74: /*
75: Run topological sort on the dependence graph; remember that the vertices are returned in the "antitopological" order.
76: This, in fact, is just what we need, since edges in the graph are entered as (client, server), implying that server
77: must be configured *before* the client and BOOSTs topological sort will in fact order server before client.
78: */
79: try{
80: ::boost::topological_sort(*(fwk->dependence_graph), std::back_inserter(antitopological_vertex_order));
81: }
82: catch(...) {
83: SETERRQ(PETSC_ERR_ARG_WRONGSTATE, "Exception caught while performing topological_sort in the dependence graph");
84: }
86: return(0);
87: }/* PetscFwkConfigure_Sort() */
88: // << C++
90: #undef __FUNCT__
92: PetscErrorCode PetscFwkViewConfigurationOrder(PetscFwk fwk, PetscViewer viewerASCII){
95: // >> C++
96: std::list<vertex_type> antitopological_vertex_order;
97: PetscFwkConfigure_Sort(fwk, antitopological_vertex_order);
98: /* traverse the vertices in their antitopological, extract component ids from vertices and configure each corresponding component */
99: /* current_state starts with 1, since 0 was used during Preconfigure */
100: for(std::list<vertex_type>::iterator iter = antitopological_vertex_order.begin(); iter != antitopological_vertex_order.end(); ++iter) {
101: PetscInt id = (*(fwk->dependence_graph))[*iter].id;
102: std::string urlstring = (*fwk->url)[id];
103: if(iter != antitopological_vertex_order.begin()) {
104: PetscViewerASCIIPrintf(viewerASCII, ", ");
105: }
106: PetscViewerASCIIPrintf(viewerASCII, "%d: %s", id, urlstring.c_str());
107: }
108: // << C++
109: PetscViewerASCIIPrintf(viewerASCII, "\n");
110: return(0);
111: }/* PetscFwkViewConfigurationOrder() */
113: #undef __FUNCT__
115: PetscErrorCode PetscFwkConfigure(PetscFwk fwk, PetscInt state){
118: // >> C++
119: std::list<vertex_type> antitopological_vertex_order;
120: PetscFwkConfigure_Sort(fwk, antitopological_vertex_order);
121: /* traverse the vertices in their antitopological, extract component ids from vertices and configure each corresponding component */
122: for(PetscInt current_state=0;current_state<=state; ++current_state) {
123: PetscObjectSetState((PetscObject)fwk,current_state);
124: for(std::list<vertex_type>::iterator iter = antitopological_vertex_order.begin(); iter != antitopological_vertex_order.end(); ++iter) {
125: PetscInt id = (*(fwk->dependence_graph))[*iter].id;
126: PetscObject component = (*fwk->component)[id];
127: PetscFwkComponentConfigure configure = (*fwk->configure)[id];
128: if(configure != PETSC_NULL) {
129: (*configure)(fwk,current_state,&component);
130: }
131: }
132: }
133: // << C++
134: return(0);
135: }/* PetscFwkConfigure() */
139: static PetscDLLibrary PetscFwkDLList = PETSC_NULL;
140: #define PETSC_FWK_MAX_URL_LENGTH 1024
142: #undef __FUNCT__
144: PetscErrorCode PetscFwkNormalizeURL_Private(PetscFwk fwk, const char url[], char nurl[], char npath[], char nname[]){
145: char *n, *s;
146: char lpath[PETSC_FWK_MAX_URL_LENGTH+1], lname[PETSC_FWK_MAX_URL_LENGTH+1];
147: char *path, *name;
148: static PetscInt nlen = PETSC_FWK_MAX_URL_LENGTH;
151: /* FIX: this should replace the filesystem path by an abolute path for real normalization */
152: /* Use local buffers if npath or nname is NULL */
153: if(npath == PETSC_NULL) {
154: path = lpath;
155: }
156: else {
157: path = npath;
158: }
159: if(nname == PETSC_NULL) {
160: name = lname;
161: }
162: else {
163: name = nname;
164: }
165: /* Copy the url so we can manipulate it inplace and also truncate to the max allowable length */
166: PetscStrncpy(path, url, nlen);
167: /* Split url <path>:<name> into <path> and <name> */
168: PetscStrrchr(path,':',&n);
169: /* Make sure it's not the ":/" of the "://" separator */
170: if(!n[0] || n[0] == '/') {
171: SETERRQ2(PETSC_ERR_ARG_WRONG,
172: "Could not locate component name within the URL.\n"
173: "Must have url = [<path>:]<name>, instead got %s\n"
174: "Remember: URL was truncated past the max allowed length of %d",
175: path, nlen);
176: }
177: /* Copy n to name */
178: PetscStrcpy(name, n);
179: /* If n isn't the whole path (i.e., there is no ':' separator), end 'path' right before the located ':' */
180: if(n != path) {
181: n[-1] = '\0';
182: }
183: /* Find and remove the library suffix */
184: PetscStrrchr(path,'.',&s);
185: /* Make sure this isn't part of a relative path name (i.e.., "./" or "../") */
186: /* FIX: we should really be using PETSc's internally defined suffices, because otherwise,
187: we might be removing names of hidden files (e.g., '${PETSC_DIR}/lib/${PETSC_ARCH}/.myhiddenlib.a') */
188: if(s[0] != '/') {
189: s[-1] = '\0';
190: }
191: PetscStrcpy(nurl, path);
192: PetscStrcat(nurl, ":");
193: PetscStrcat(nurl, name);
194: return(0);
195: }/* PetscFwkNormalizeURL_Private() */
197: #undef __FUNCT__
199: PetscErrorCode PetscFwkInsertComponent_Private(PetscFwk fwk, const char url[], PetscObject component, PetscFwkComponentConfigure configure, PetscInt *_id){
200: /*
201: WARNING: This routine will not check whether url has already been registered.
202: It will assign a new id to the url and insert the corresponding component and configure objects.
203: */
204: PetscObject old_component;
205: PetscInt id;
208: // >> C++
209: std::string urlstring(url);
210: // Check whether url has already been registered
211: if((*(fwk->id)).count(urlstring)) {
212: // Retrieve the existing id
213: id = (*(fwk->id))[urlstring];
214: // Reset the existing component and configure objects
215: old_component = (*(fwk->component))[id];
216: if(old_component) {
217: PetscObjectDereference(old_component);
218: }
219: if(component) {
220: PetscObjectReference(component);
221: }
222: (*(fwk->component))[id] = component;
223: (*(fwk->configure))[id] = configure;
224: }
225: else {
226: // Assign and store the new id for urlstring.
227: id = (*(fwk->id)).size();
228: (*(fwk->id))[urlstring] = id;
229: (*(fwk->url)).push_back(urlstring);
230: /* Push new component and configure objects onto the list */
231: if(component) {
232: PetscObjectReference(component);
233: }
234: (*(fwk->component)).push_back(component);
235: (*(fwk->configure)).push_back(configure);
236: /* Add a new vertex to the dependence graph. This vertex will correspond to the newly registered component. */
237: vertex_type v = ::boost::add_vertex(*(fwk->dependence_graph));
238: /* Attach id to v */
239: (*(fwk->dependence_graph))[v].id = id;
240: /* Store v in fwk */
241: (*(fwk->vertex)).push_back(v);
242: }
243: // << C++
244: if(_id) {
245: *_id = id;
246: }
247: return(0);
248: }/* PetscFwkInsertComponent_Private()*/
251: #undef __FUNCT__
253: PetscErrorCode PetscFwkRegisterComponentWithID(PetscFwk fwk, const char url[], PetscInt *_id){
254: PetscFwkComponentConfigure configure = PETSC_NULL;
255: PetscObject component = PETSC_NULL;
256: char nurl[PETSC_FWK_MAX_URL_LENGTH+1], path[PETSC_FWK_MAX_URL_LENGTH+1], name[PETSC_FWK_MAX_URL_LENGTH+1];
257: char sym[PETSC_FWK_MAX_URL_LENGTH+26+1];
258: //PetscInt id;
259: MPI_Comm comm;
262: PetscFwkNormalizeURL_Private(fwk, url, nurl, path, name);
263: // >> C++
264: // Check whether a component with the given url has already been registered. If so, return its id, if it has been requested.
265: std::string urlstring(nurl);
266: if((*(fwk->id)).count(urlstring)) {
267: if(_id) {
268: *_id = (*(fwk->id))[urlstring];
269: }
270: return(0);
271: }
272: // Insert a new url with empty corresponding component and configure objects
273: PetscFwkInsertComponent_Private(fwk, nurl, PETSC_NULL, PETSC_NULL, PETSC_NULL);
274: /* Build the configure symbol from name and standard prefix */
275: PetscStrcpy(sym, "PetscFwkComponentConfigure");
276: PetscStrcat(sym, name);
277: /* Load the library designated by 'path' and retrieve from it the configure routine designated by the constructed symbol */
278: PetscObjectGetComm((PetscObject)fwk, &comm);
279: PetscDLLibrarySym(comm, &PetscFwkDLList, path, sym, (void**)(&configure));
280: /* Run the configure routine, which should return a valid component object */
281: (*configure)(fwk, 0, &component);
282: if(component == PETSC_NULL) {
283: SETERRQ2(PETSC_ERR_LIB, "Configure routine %s from library %s returned a NULL component", path, sym);
284: }
285: /* Reinsert nurl with the correct component and configure objects, and retrieve its id. */
286: PetscFwkInsertComponent_Private(fwk, nurl, component, configure, _id);
287: return(0);
288: }/* PetscFwkRegisterComponentWithID()*/
290: #undef __FUNCT__
292: PetscErrorCode PetscFwkRegisterComponent(PetscFwk fwk, const char url[]){
295: PetscFwkRegisterComponentWithID(fwk, url, PETSC_NULL);
296: return(0);
297: }/* PetscFwkRegisterComponent()*/
300: #undef __FUNCT__
302: PetscErrorCode PetscFwkRegisterDependence(PetscFwk fwk, const char clienturl[], const char serverurl[])
303: {
304: PetscInt clientid, serverid;
309: /* Register urls */
310: PetscFwkRegisterComponentWithID(fwk, clienturl, &clientid);
311: PetscFwkRegisterComponentWithID(fwk, serverurl, &serverid);
313: /*
314: Add the dependency edge to the dependence_graph as follows (clienturl, serverurl):
315: this means "client depends on server", so server should be configured first.
316: For this reason we need to order components using an "antitopological" sort of the dependence_graph.
317: BOOST Graph Library does just that, but keep that in mind if reimplementing the graph/sort in C.
318: */
319: vertex_type c,s;
320: c = (*(fwk->vertex))[clientid];
321: s = (*(fwk->vertex))[serverid];
322: ::boost::add_edge(c,s, *(fwk->dependence_graph));
323: return(0);
324: }/* PetscFwkRegisterDependence()*/
328: #undef __FUNCT__
330: PetscErrorCode PetscFwkDestroy(PetscFwk fwk)
331: {
333: // >> C++
334: delete fwk->id;
335: delete fwk->url;
336: delete fwk->configure;
337: delete fwk->component;
338: delete fwk->vertex;
339: delete fwk->dependence_graph;
340: // << C++
341: PetscHeaderDestroy(fwk);
342: fwk = PETSC_NULL;
343: return(0);
344: }/* PetscFwkDestroy()*/
346: #undef __FUNCT__
348: PetscErrorCode PetscFwkCreate(MPI_Comm comm, PetscFwk *framework){
349: PetscFwk fwk;
352: /*#if !defined(PETSC_USE_DYNAMIC_LIBRARIES)*/
353: PetscFwkInitializePackage(PETSC_NULL);
354: /*#endif*/
356: PetscHeaderCreate(fwk,_p_PetscFwk,PetscInt,PETSC_FWK_COOKIE,0,"PetscFwk",comm,PetscFwkDestroy,0);
357: // >> C++
358: fwk->id = new std::map<std::string, PetscInt>;
359: fwk->url = new std::vector<std::string>;
360: fwk->configure = new std::vector<PetscFwkComponentConfigure>;
361: fwk->component = new std::vector<PetscObject>;
362: fwk->vertex = new std::vector<vertex_type>;
363: fwk->dependence_graph = new dependence_graph_type;
364: // << C++
365: *framework = fwk;
366: return(0);
367: }/* PetscFwkCreate() */
369: #undef __FUNCT__
371: PetscErrorCode PetscFwkGetComponentByID(PetscFwk fwk, PetscInt id, PetscObject *component) {
373: // >> C++
374: try{
375: *component = (*fwk->component)[id];
376: }
377: catch(...){
378: SETERRQ1(PETSC_ERR_ARG_WRONG, "Couldn't retrieve PetscFwk component with id %d", id);
379: }
380: // << C++
381: return(0);
382: }/* PetscFwkGetComponentByID() */
384: #undef __FUNCT__
386: PetscErrorCode PetscFwkGetComponent(PetscFwk fwk, const char url[], PetscObject *component) {
389: // >> C++
390: try{
391: *component = (*fwk->component)[(*fwk->id)[url]];
392: }
393: catch(...){
394: SETERRQ1(PETSC_ERR_ARG_WRONG, "Couldn't retrieve PetscFwk component with url %s", url);
395: }
396: // << C++
397: return(0);
398: }/* PetscFwkGetComponent() */
400: #undef __FUNCT__
402: PetscErrorCode PetscFwkFinalizePackage(void){
405: PetscFwkPackageInitialized = PETSC_FALSE;
406: if(PetscFwkDLList != PETSC_NULL) {
407: PetscDLLibraryClose(PetscFwkDLList);
408: PetscFwkDLList = PETSC_NULL;
409: }
410: return(0);
411: }/* PetscFwkFinalizePackage() */
415: #undef __FUNCT__
417: PetscErrorCode PetscFwkInitializePackage(const char path[]){
420: if(PetscFwkPackageInitialized) {
421: PetscFwkPackageInitialized = PETSC_TRUE;
422: }
423: /* Regster classes */
424: PetscCookieRegister(PETSC_FWK_CLASS_NAME, &PETSC_FWK_COOKIE);
425: PetscRegisterFinalize(PetscFwkFinalizePackage);
426: return(0);
427: }/* PetscFwkInitializePackage() */