Some notes about this and that.

How to compile

Caution:   Current makefiles that are provided with source code are optimized for LINUX RedHat-6.2 (7.0)  running on PC.  If you have another hardware-OS configuration you must use options that ROOT uses for that particular configuration. This is exactly what I did in the beginning: I took Makefile from directory $ROOTSYS/test  ( assuming you have ROOT running on your system already) and copied all options into my Makefiles. I did this procedure one more time because ROOT changed during last year, and therefore if you download new version of ROOT and you program stops working , first thing to do is to check whether new options to compiler are needed.  Basically they must be the same as of the current ROOT package has.

 

 
 
 
 

There is a Makefile in every subdirectory with source code. Simply saying "make" in every subdirectory will compile and link code into shared libraries and into programs if any.
User file must be added to Makefile and "make depend" command must be given for  make utility to correctly adjust all dependencies.
There is also Makefile in SasyHomeDir which simply goes around all subdirectories and calls makefiles in them.
First library to compile must be "kernel" library libTot.so. Source code for it is in ./src . All other libraries depend on it.  Other libraries may be compiled in any order ( at the moment they do not depend on each other and I want to keep them this way by separating mutually dependent makers into separate libraries. Executable programs of course must be compiled and linked last because they depend on all shared libraries.

How to compile smaller executables and shared libraries and speedup processing.

Trick is in options to compiler. Usually during development I use debug options and I do not do optimizations of assembled code (SasyMakeOption='-D_DEBUG_KA_ -g'). Libraries tend to be tens of megabytes size and program runs slower for one simple reason - those libraries take up space in memory, which is not infinite and system resorts to swapping. And of course code is not optimized - it makes it slower too. So,  I  set environment variable SasyMakeOption='-D_DEBUG_KA_ -O3' . Libraries became considerably smaller (several times) and it takes less time to load them now.
If you are sure that certain code runs OK on certain data than you may go even further - take out -D_DEBUG_KA_.
This option defines macro _DEBUG_KA_    and then program executes additional user checks during execution, things such as array range checking,  Phi <= TWOPI, Theta <=PI and so on.
It is helpfull during development to put in such checks, even if you are 100% sure that it works. Just sandwich  it between  #ifdef _DEBUG_KA_   and #endif. It will not be executed if you take the mentioned above option from compiler command in Makefiles.

Also, you may turn off all statements "assert"  in your program if you use option "-DNDEBUG".
So, fastest program will be if you use "-O3 -DNDEBUG".

How to debug
First of all you need to change flags to compiler, in bash:
export SasyMakeOption='-D_DEBUG_KA_ -g'
first flag tells program to execute code sandwiched  between  #ifdef _DEBUG_KA_   and  #endif. Second flag tells compiler to make debug version of executable. Standard debuggers then can be used to do debugging.
 

How to speedup reading of data files by reading only portion of an event data  and deciding if you want to read the rest of event or not.

Use ./src/LegsSelectorBranchStatus.*  which allows user to specify which variables of event should be read always, which variables should be read only if certain preliminary cuts are satisfied and which variables should NEVER be read.  The variables may be flagged as "NEVER to read"  in LegsSelectorBranchStatus::Init(). The preliminary cuts may be put in in LegsSelectorBranchStatus::Make().  If you want the whole event to be read (excluding variables that are marked " NEVER to read" ) - return kTRUE.
Otherwise return kFALSE and the event will not be read any further. Only those variables that are marked "read always" and are used to place preliminary cuts are read. Sample cuts would be:  read only events when XT and PN are hit. Experience shows that such simple cuts may reduce processing time several times.
One should not forget about these cuts though. They apply to ALL events, to ALL makers, ALWAYS untill you specifically turn them off.
 
 

How to make event lists ( speedup also)

There is analog of PAW mask in ROOT - event list.
First you create event list by adding to your maker's Make() function statement : it->AddToEventList().
This adds event to event list into file named after this maker, say maker's name is MUMU, then file created will be ./eventLists/MUMU_list.root.

Later when you want to look only at events which satisfied the maker above you have to say after declaration of LegsRun object:

theRun->SetEventList("MUMU");
this will make sure that looping will be done only on events from the list.

Again, you have to remember that these kind of preliminary cuts apply to ALL makers, ALWAYS untill you specifically turn them off.
 
 

Adding Your Own Classes to SasySoft


Forst you need to create your working place:

  1. Create your own directory  $SasyHomeDir/MyDir".
  2. Copy a Makefile from directory  $SasyHomeDir/maker1 ( or any other which contains makers only) to MyDir
  3. Edit Makefile: substitute name of directory  on top line for "MyDir" and edit list of makers on second line according to your makers names.


You can create new makers most easily by editing  a copy of existing  makers which do almost what you want to do.

  1. Copy a maker which most resembles what you want to do from any of directories which contain makers only ( maker1, maker2,makersim,calibrations ...)  to this directory.
  2. Rename the maker's header file  into LegsMakerMyMaker.h
  3. Rename the maker's implementaion file  into LegsMakerMyMaker.cxx
  4. Edit Makefile and substitute name(s) of maker(s) with your maker's name.
  5. Add you Makefile name to list of available Makefiles in "top makefile"  $SasyHomeDir/Makefile so that it is called automatically when SasySoft is recompiled.
  6. make
  7. debug
  8. make
  9. debug
  10. .........
  11. .......   Good luck

 
 
 
 
 

More detailed


If you want to integrate your classes into the SasySoft system, you have to add the following line to your class header files (as part of
the public part of the class definition):

   ClassDef(ClassName,ClassVersionID)  //The class title

See for example LegsMakerSample.h. The ClassVersionID is used by the ROOT I/O system. It is written on the output stream and during reading you can check this version ID and take appropriate action depending on the value of the ID ( not really used  by me at all  05/23/00). Every time you change the layout of a class you should increase its ClassVersionID by one. The ClassVersionID should be greater or equal  to 1. Set ClassVersionID=0 in case you don't need object IO support. Generally for makers it is needed to be able to have histos automatically written into output root file.

NOTE: the ClassDef macro must be the last item before the closing '};' in a class definition.  It contains its own private and public tags so it can be added to either a private or public part of a
class definition.

Similarly, in your implementation file you must add the statement:

   ClassImp(ClassName)

See for example LegsMakeSample.cxx. Note that you MUST provide a default constructor for your classes, i.e. a constructor with zero parameters or with one or more parameters all with default values in case you want to use object I/O. If not you will get a compile time error.

The ClassDef and ClassImp macros are defined in the file Rtypes.h. This file is referenced by all ROOT include files, so you will automatically get them if you use a ROOT include file.

The ClassDef and ClassImp macros are necessary to link your classes to the dictionary generated by CINT to get access to the RTTI and object I/O features of ROOT. The RTTI system allows
you to, a.o. find out to which class an object belongs, its baseclasses, its datamembers and methods, the method signatures, etc. This information is used to make advanced object browsers and
by the automatic documentation generation system. The object I/O system allows you to store and retrieve objects (and arbitrarily complex object structures) from a ROOT database.

If you are only interested in interactive access to your classes via the command line or macro processor you do not need to use the ClassDef and ClassImp macros.
 

So much for ROOT requirements. Now SasySoft requirements:

Unique feature of SasySoft is that it's makers have to be children-classes of one class "LegsMaker".

Here is simplified header for the class:
 

class LegsMaker: public TDirectory
{

 public:

  LegsMaker(){;}
  LegsMaker(const Text_t *name,const Text_t *title, LegsRun* theRun = NULL,const int add = 1);

  virtual ~LegsMaker(){;}

  virtual void Init(); //! initializes all histograms and other member variables.
  virtual Bool_t Make(); //! called by LegsRun every event when LegsRun::Loop() is called.
  virtual void RunEnd(); //! called at the end of run

  Bool_t fDo;//!

 protected:

  LegsRun* it; //!
  ClassDef(LegsMaker,3) // Base class for all makers
};
 

As you can see it has two constructors, one allowing passing of parameters such as name and title. The other "default" constructor is present to make ROOT happy.
Virtual destructor is also something ROOT and C++ decided they need to have.
Then three "useful" functions follow. Comments say it all.

The fDo data member is there to make possible for SasySoft to turn on and off a maker when interactively looking at events with 3D display. If fDo is true, then the maker will be used.
Of course in a batch fDo should be always true.  User should not mess with this flag. If you don't want maker to be processed in batch - don't declare it. In future if I do not forget I will protect similar variables so that user can't mess it up.

Well, pointer to the run which is being processed is stored in "it".

Last line has been described above in ROOT's requirements.
 

Here is a sample maker:
 

class LegsMakerSample: public LegsMaker
{

 public:
  // data members :
  TH1F* fHistPol;

  // standard functions MUST exist in order to link to LegsRun.
  LegsMakerSample(int add = 1);
  virtual ~LegsMakerSample(){;}
  void Init(); // books all histograms and other member variables.

  Bool_t Make(); // called by LegsRun every event when LegsRun::Loop() is called.
  // this is the main function from which other functions can be called.

  void RunEnd(); // executed at end of run, called by LegsRun::RunEnd()
  // here one may do whatever he wants.
 

  // user functions may be HERE
  // but better style is to put them into private section
 protected:

  // user code HERE

 private:
  // user code HERE

  ClassDef(LegsMakerSample,2) // Sample user maker
};
 
 

Of course this sample source is not as uptodate as the source files themselves are - if in doubt, look at the files in "reference guide".
 
 

OK, I hope I gave an idea of what the makers are.

See "CINT as Dictionary Generator" for a detailed description on how to generate a dictionary.
 

How to make distribution-exchange file


There is a script called dist.sh in directory $SasyHomeDir/scripts.
Running this script should clean all source directories of object files, libraries, core files, and twobody kinematics lookup tables and then tar
needed files into one archive named SasySoft_vXXX.tar.gz. This file is all that is needed to setup the system on another machine.

Caution:  script dist.sh relies on naming convention that all maker directories are in $SasyHomeDir and have prefix "maker". So if you create new directory of your own makers and put it into subdirectory of $SasyHomeDir named maker* then it will be automatically added to distribution.
 

Suggested  reasonably simple  naming scheme for distribution files:

SasySoft_vXXX_YourInitialsHere.tar.gz

this would tell that "kernel" part of the program ( the one that resides in src directory)  is version number XXX and makers (in maker* directory) are modified by you.  It is very bad idea to change makers that reside in other peoples directories.  It is much better to copy what you need into your new directory and keep all changes to that directory. This way it is very easy to work with code and track changes and errors.

Changing kernel part od SasySoft by many people independently  seems to be trouble - nobody will find any tracks of anything and the whole idea of having standard analysis interface will be only dream and the program slowly will diintegrate into little pieces of what diferent people managed to accomplish but the pieces will not add up together...

I guess frequent workshop meetings and one standard well documented version of SasySoft kernel for all is needed desperately just as one ROOT version and one version of  NQ are needed.
 

One can have several versions of SasySoft installed simultenuosly and switch between them by changing environment variable SasyHomeDir.

  1. cd $SasyHomeDir
  2. . ./scripts/dist.sh
  3. mkdir ~/newSasy
  4. cp SasySoft_vXXX.tar.gz  ~/newSasy
  5. cd ~/newSasy
  6. export SasyHomeDir=~/newSasy
  7. tar -xzvf SasySoft_vXXX.tar.gz
  8. make depend
  9. make


should work now.
It will use same directories for data and output results, but different calibration parameters.
 

How to pass STL vector as parameter in member-function


STL does not live in peace with ROOT on many occasions. This time compromise is possible.
Look at LegsPart constructor that takes vector as parameter. If I simply put declaration of clump below declaration of the constructor it stops working !
So, in order to pass some vector around as parameter you need to declare one in header file first.