Serban Oct.1997 FRAMEWORK PROPOSAL ================== I would like to make a proposal for discussion that I believe should be easy to implement with what Scott and Gordon have done so far. It makes use of the concept of streams that Gordon presented at the last meeting (as far as I can tell streams are basically the equivalent of hooks in run I). The proposal consists of the following items: 1) There is a program builder (python script of python scripts?) that constructs a main program and each stream. It also must construct a make file for compilation and linking, and, if appropriate, a command file to define any symbols needed for execution. 2) A main program is a set of calls to streams inside appropriate loops (initialization, event loop, etc). Which streams and how they go into making a particular program is handled via a python script. 3) A stream consists of series of calls to a method from interface classes for each package that must be called inside the stream. Only one method per stream. 4) In each stream there are a couple of tokens passed as arguments to the method. What the tokens are depend on the stream, most often they are pointers to the event object or to some output file. The token definition is part of the stream definition. 5) Each package must come with an interface class that has methods corresponding to the streams this package is expected to be part of, and each package has a python script itemizing the appropriate streams it contributes to. The script needs to indicate package dependencies, information that can be used to ensure packages are called with the right time sequence. 6) For any given program a python script describes what packages are to be used and in what order. The program behavior should be changed only by editing the script (not the generated code). I like to clarify and expand a bit on the above points: a) We should build the first version of the reconstruction by hand following the above plan. The program builder should be implemented afterwards, not before. b) It has been suggested that the stream token be very general, in a way similar to the event. Stuff can be inserted in the token and a protocol provided for extracting appropriate items (like the event pointer). I do NOT like that approach. I believe it adds an unnecessary level of complexity to ask each package to follow yet another protocol to extract pointers when we already have an elaborate protocol for inserting and extracting information in the event. A stream should pass one or two simple tokens around that are specific to that stream, ie part of the stream definition. We should ensure that each stream performs a specific function and not a mixture of functions. A complex general token opens the door for mixing functions that should not be mixed. c) In general, there is no reason why methods from packages will want to be called in the same order in every stream. If we want to make that general then a program script will have to contain a list of streams and an ordered list of packages for every stream where the order matters. We should look at frameworks planned for other experiments to see if there are important features needed that we may be neglecting following my proposal. I am not in favor of explicitly adopting another experiment framework if it comes with the overhead of having to buy into some elaborate system extraneous to the framework itself (like using TCL instead of python). Below is an explicit example of a program that follows the rules I proposed. It is only meant as an example of how it could be implemented, I am not suggesting it be done that way. Note that the packages are passed as arguments to the streams, the order of execution is the order of the arguments. For perverse reasons I chose a different package order for each stream. We could chose to make the stream classes rather than global functions and construct lists of packages instead, my example is purely a proof of principle. I put the token definitions in the main program. We could make the choice of putting some inside the streams themselves, this would imply that in the case of dump event there would be a separate dump file for each event. I also indicated the event dump is conditional by having a conditional check before calling the package methods. The program script must include instructions on how to make the conditional function. Note that the syntax can be slightly different from stream to stream so that we will need different scripts for each stream. All lines of code are expected to be made eventually by some a program builder. At the moment I am ignoring some possible complications (like multiple iterations trough some package, multiple event processing, etc.). These complications need to be though through before we can settle on a specific implementation. // EXAMPLE PROGRAM #include #include "IO_pack.hpp" #include "user1.hpp" #include "user2.hpp" // stream headers bool stream_ini(IO_pack &io,User_pack1 &user1, User_pack2 &user2); bool stream_read_event(IO_pack &io, Event* evtptr); void stream_process_event(User_pack1 &user1, User_pack2 &user2, Event* evtptr); void stream_dump_event(User_pack2 &user2, User_pack1 &user1, ofstream &dump, Event* evtptr); void stream_write_event(IO_pack &io, Event* evtptr); void stream_summary(User_pack1 &user1, User_pack2 &user2, IO_pack &io, ofstream &summ); // end of stream headers // main program int main(){ IO_pack io; User_pack1 user1; User_pack2 user2; if(stream_ini(io,user1,user2)){ // skip everything if initialization fails ofstream dump("event.dump"); Event *evtptr=0; // event loop do{ if(stream_read_event(io, evtptr)){ stream_process_event(user1, user2, evtptr); stream_dump_event(user2, user1, dump, evtptr); stream_write_event(io, evtptr); } }while (evtptr !=0 ); // end of event loop ofstream summ("summary.out"); stream_summary(user1, user2, io, summ); }else{ // failing package is assumed to generate some appropriate message // but we may want something more here return 1; } return 0; } // end of main // stream implementations bool stream_ini(IO_pack &io,User_pack1 &user1, User_pack2 &user2){ bool good=true; good=good && io.ini(); good=good && user1.ini(); good=good && user2.ini(); return good; } bool stream_read_event(IO_pack &io, Event *evtptr){ bool good=true; good=good && io.read_event(evtptr); return good; } void stream_process_event(User_pack1 &user1, User_pack2 &user2, Event *evtptr){ user1.process_event(evtptr); user2.process_event(evtptr); } void stream_dump_event(User_pack2 &user2, User_pack1 &user1,ofstream &dump, Event* evtptr){ if(some_condition(evtptr)){ user2.dump_event(dump, evtptr); user1.dump_event(dump, evtptr); } } void stream_write_event(IO_pack &io, Event* evtptr){ io.write_event(evtptr); } void stream_summary(User_pack1 &user1, User_pack2 &user2, IO_pack &io, ofstream &summ){ user1.summary(summ); user2.summary(summ); io.summary(summ); }