BEMC-Decoupled Trigger Utilities For PicoDst Production from MuDsts (Detailed)

I have been working on isolating and extracting the relevant BEMC trigger code from StTriggerSimuMaker in order to simulate and store the trigger information in picoDst production from MuDsts. In order to accomplish this, the Trigger Threshold tables needed to be migrated from the online database to the offline database, to avoid numerous online calls during picoDst production. This has been accomplished and information regarding the migration can be found at my previous blog posts. I now have a working bemc-decoupled trigger simulator code that I will outline what it does and how to use it in this blog post.

Naming Convention:
For now, without much consideration, I have named the directory holding my maker StSimpleTriggerUtilities, and the head maker is named StSimpleTrigSimuMaker. I kept the name conventions close to, but not the same as, what is found in StTriggerUtilities. I wanted to avoid namespace issues while making it obviously clear which files correspond to the original StTriggerUtilities. One example is Bemc/StBemcTriggerSimu.cxx -> StBemcTrigSimu.cxx.

Some History:
My bemc-isolated code (from here on denoted as StSimpleTriggerUtilities) is significantly shorter then StTriggerUtilities' bemc code. The reason for this is that, prior to 2009, each of the yearly dsm algorithms were coarsely added into StTriggerUtilities/Bemc/StBemcTriggerSimu, with many lines of code denoted to simulating the triggers unique to a year. After 2009, a more elegant solution was introduced, which stored the dsm algorithms in a subdirectory, StDSMUtilities. Also, after 2009 the trigger information was changed to being read in from the database, as opposed to hard coding it in inside the code. In order to keep the old hard-coded functionality for years prior to 2009, inside StTriggerUtilities you will find that most functions have duplicates, one pre-2009 and one post-2009. For my code I only extracted the post-2009 functionality.

<<<What it does>>>:

0) Initialization:
  StSimpleTriggerUtilities, my bemc-isolated code, can only function if StEmcADCtoEMaker is within the chain. On initialization, it creates an object of the class StBemcTrigSimu, which does most of the leg work. I could have just put all the functionality inside of the head maker, but I wanted to be consistent with the original StTriggerUtilities and leave room for expansion if necessary. The StBemcTrigSimu object then gets access to StEmcADCtoEMaker from the chain, and then gets access to StBemcTables, which is used to retrieve information regarding status of the towers and pedestal values.

1) Reading In Database and Setting DSM Registers:
  StSimpleTriggerUtilities, on initRun(int runnumber), then reads in the Trigger Threshold values from the offline database. The relevant thresholds that are  read in are always found in the same location. In the notation of the database, the thresholds for the HT trigger are found at object=5,index=16,reg=X  and also at object=6,index=16,reg=X  where X stands for 0,1,2,3 for bht0, bht1, bht2 and bht3. Sometimes the database has information regarding higher registers, which may belong to other triggers, such as BEMC-HT-UPC, which is not supported in my code. The higher registers are still read in and stored, but are not used. The registers (or thresholds values) are stored in DSMLayer objects, which perform the DSM algorithms. For the HT trigger, it is stored in DSM_Layer0.

The thresholds for the JP trigger are found at object=2.index=33,reg=X where X stands for 0,1,2, which stands for JP0,JP1, and JP2. For years in which there are no JP triggers, such as 2014 and 2016, object=2,index=33,reg=0 does not contain the register for JP0, but instead contains other information. For all the runs I checked it seems to be consistently 4. For these years Registers 1 and 2 are not set, and thus are 0. For Run 15, there are some trigger setups which have 3 versions of JP2, such that JP2-East, JP2-Mid, and JP2-West have different threshold values. For example, for 2015 sometimes object=2,index=33,reg=4 is JP2-West. It is important to note, that for other years this same register could hold different information. For example, in 2013, the object=2,index=33,reg=4 can be the dijet trigger threshold. When reading the registers, one has to know before hand what its use is.

2) Calculating dsmADC

  For each run, StBemcTrigSimu::FEEini(runnumber) is called. This reads in the tower pedestal from StBemcTables, and converts it to the FEE pedestal. This is done through the code located at Bemc/BEMC_DSM_decoder.cxx which is taken directly from StTriggerUtilities. Also in FEEini, an array named bitconvvalue[# of towers] is set by calling StBemcTables::getTriggerBitConv. This seems to be an unnecessary step, as, from what I understand from Zilong, these tables aren't always up to date, and for physics runs the bitconvvalue is always set to 2. This bitconvvalue's only use is as an input for calculating the tower dsmADC values.

For each event, StBemcTrigSimu::FEEout() is called. This function loops over bemc hits and calculates the tower and trigger patch dsmADC values. These are stored as arrays and are the inputs into the DSM algorithms. As it turns out, for the sake of the HT trigger, the dsm algorithms are not necessary, and the tower dsmADC values calculated here, along with the thresholds read in from step 1, are all that is necessary. There are return functions that can be called to retrieve the tower dsmADC values.

3) DSM Algorithms
 For each event, after FEEout(), if the Run is not 14 or 16, then the DSM algorithms are called through getDSMLayer0(runnumber) and getDSMLayer1(runnumber). The output of DSMLayer0 is used as input to DSMLayer1. The individual DSMLayer objects call the appropriate run year DSM algorithms. For layer 0, there are 4 different algorithms, BE001, BE003, BW001, and BW003. For layer1 there is only one algorithm, BC101. Inside these algorithms is where the jet patch dsmADC values are calculated. It is important to note that a lot of the differences between the yearly dsm algorithms are to the outputs and the reading of certain registers; the jet patch dsmADC calculation (which occurs in DSM_Algo_BC101_20XX) is mostly unchanged. This is why for years 20010-2012 the dsm2009 algorithm can be called.

The DSMLayers and utilities can be found in StSimpleTriggerUtilities/DSMUtilities. The year specific DSM algorithms can be found in DSUtilities/dsm20XX. Currently there are 3 versions, 2009 (valid 2009-2012 and some runs in 2013), 2013 (valid for rest of runs in 2013), and 2015 (valid for 2015). There is currently no point in going through DSM algorithms for 2014 and 2016 when there are not jet patch triggers. The jet patch adc values are stored in the DSM objects, inside an array called info[]. DSMLayer_BC101 contains 6 DSM objects, each which stores 3 jp dsmADC values. info[0] = jpx dsmADC value, info[1] = jpy dsmADC value, info[2] = jpz dsmADC value, where jpx, jpy, jpz stand for the east, mid, and west jet patches. This totals to 18 bemc jet patches.

Although in the full StTriggerUtilities this is not the end, for my bemc-decoupled simulator StSimpleTriggerUtilities this is as far it needs to be. All of the necessary information has been calculated.

Using StSimpleTriggerUtilities in PicoDstProduction:

Before I started working on my decoupled code, someone (not sure who) already had StPicoDstMaker using StTriggerUtilities and store emcTrigger information. I mimicked what has already been done, with some minor changes to account for year 2015. The 5 relevant functions to retrieve the information are:

StSimpleTriggerSimuMaker* trigSimu = (StSimpleTriggerSimuMaker*)GetMaker("StarSimpleTrigSimuMaker");

int HTthreshold = trigSimu->bemc->barrelHighTowerTh(x);    //Where x = 0,1,2,3...  to get the HT thresholds

int TowerDsmADC = trigSimu->bemc->barrelHighTowerAdc(towerId);  //where towerId=1...4800   

int JPthreshold = trigSimu->bemc->barrelJetPatchTh(x);  //where x = 0,1,2  to get the JP thresholds (for 2015, x can also be 3 or 4 for JP2 mid and JP2 west)

int JPdsmADC = trigSimu->bemc->barrelJetPatchAdc(jp);  //where jp = 0..17   total of 18 jet patches

In StPicoDstMaker, the dsmADC values are compared to the thresholds, and if the dsmADC value is greater than the threshold, then the information will be saved in an StPicoEmcTrigger object, which stores the flag (which triggers it satisfied), the towerID/jet patch id which satisfied the trigger, and the dsmADC value of said tower/jetpatch. Some important remarks:

The thresholds for the HT and JP triggers are stored inside StPicoEvent.

The flag stored is an unsigned int, which contains 16 bits. The flag stores what thresholds were exceeded by setting the bit which corresponds to a specific threshold to 1.

As of now, which may be subject to change, the bits are assigned such that:

Bit Trigger
0 BHT0
1 BHT1
2 BHT2
3 BHT3
4 BHT4
5 UNUSED
6 JP0
7 JP1
8 JP2(east)
9 JP2(mid)
10 JP2(west)
11 UNUSED
12 UNUSED

Important to note that because the triggers are filled and stored by looping over the towers and jet patches, no StPicoEmcTrigger object will have JP bits and HT bits assigned, it has to be one or the other.

Here is an example(2015): A tower has and dsmADC value which surpassed threshold for BHT0 and BHT1, but not BHT3. This means the first few bits would be 011, so the flag would be stored as 3.In an analysis, if you want to check for a tower satisfying BHT1, you would loop over the StPicoEmcTrigger objects, and search for the condition(flag & 0x2).

The obviously drawback is that this isn't the most user friendly way to store the trigger information, but it is rather space efficient. If this seems unsatisfactory, another option is to add a function in StPicoEvent which interprets the emcTrigger info and displays it in a more user friendly manner.

Considering the length of this blog entry, I am going to make another blog entry skipping the details of the code outlined here and simply discuss the relevant information for users.