EventProcessor state transitions

The current design of the art EventProcessor class contains a state machine that controls some features of the data processing. In particular, the state machine controls when a series of actions are invoked on modules, input and output files, caches of run and subrun data, etc..

The state machine interacts with the EventProcessor only through the abstract interface defined by IEventProcessor. This interface exists in large part for testing purposes; tests can drive an instance of the state machine connected to an instance of MockEventProcessor, which implements these functions by writing text indicating which function was called. The test can be used to understand the intended behavior of the state machine.

As of art v0.4.1, when this snapshot was taken, the functions of EventProcessor invoked by the state machine are:

    virtual StatusCode runToCompletion(bool onlineStateTransitions);
    virtual StatusCode runEventCount(int numberOfEventsToProcess);
    virtual void readFile();
    virtual void closeInputFile();
    virtual void openOutputFiles();
    virtual void closeOutputFiles();
    virtual void respondToOpenInputFile();
    virtual void respondToCloseInputFile();
    virtual void respondToOpenOutputFiles();
    virtual void respondToCloseOutputFiles();
    virtual void startingNewLoop();
    virtual bool endOfLoop();
    virtual void rewindInput();
    virtual void prepareForNextLoop();
    virtual void writeSubRunCache();
    virtual void writeRunCache();
    virtual bool shouldWeCloseOutput() const;
    virtual void doErrorStuff();
    virtual void beginRun(int run);
    virtual void endRun(int run);
    virtual void beginSubRun(int run, int subRun);
    virtual void endSubRun(int run, int subRun);
    virtual int readAndCacheRun();
    virtual int readAndCacheSubRun();
    virtual void writeRun(int run);
    virtual void deleteRunFromCache(int run);
    virtual void writeSubRun(int run, int subRun);
    virtual void deleteSubRunFromCache(int run, int subRun);
    virtual void readEvent();
    virtual void processEvent();
    virtual bool shouldWeStop() const;
    virtual void setExceptionMessageFiles(std::string& message);
    virtual void setExceptionMessageRuns(std::string& message);
    virtual void setExceptionMessageSubRuns(std::string& message);
    virtual bool alreadyHandlingException() const;

The EventProcessor has a several different modes of running, and the behavior of the some transitions depends on the mode of running. These behaviors seem to be the cause of some confusion in CMS; we should discuss what degree of complexity is required by the Intensity Frontier experiments, and consider simplifying the state machine to reflect this.

What seems most confusing to users is when beginRun and endRun, and beginSubRun and endSubRun get called. Perhaps these functions are just poorly named. For example endRun is called not only when we transition from one run to the next, but also when we close an output file (so that entries can be written to the Run object that will be written out before that file is closed). I am not sure if beginRun is called when the next file is opened. In addition, the state machine can be in different modes determining whether begin/end run and subrun will be called for empty runs and subruns (empty means containing no events).

We should also evaluate the maintainability of state machine code written using the boost::statechart library. In particular, does the use of a template-based embedded DSL as the basis of the state machine yield more maintainable code than would the use of an external DSL and code generation (e.g., from using SMC).