Workbook for SLD Offline Users - Data Exercise 1: Using Data Banks

In the First Daysection of the Workbook we ran an IDA session where we looked at and plotted the inverse transverse momentum of charged particles, using "PEEK _PHCHRG(1).HLXPAR(2)" and "HIST PHCHRG%(HLXPAR(2)) FROM 0 TO 10" commands. At that time we had to take it on faith that we were plotting the appropriate quantities and accessing them correctly. In this section we will look more closely at the PHCHRG bank in an attempt to understand how to extract the information we need from it and other jazelle banks.


Get a copy of PHCHRG.TEMPLATE in your editor. You can do this by typing:
   > eve ducssearch:phchrg.template
where ducssearch is one of the DUCS logical names we learned about in the previous section of the Workbook.

Template Headers

At the top of your screen you should see something like this:
   !---------------------------------------------------------------------*\
   !==> Mini DST bank containing track information                        |
   !----------------------------------------------------------------------|
   ! KEYWORDS: MINI-DST                                                   |
   !*--------------------------------------------------------------------*|
   !                                                                      |
   !     OWNER: Homer                  CO-OWNER: Hildreth                 |
   !   SECTION: DST                        FILE: PHCHRG TEMPLATE          |
   !                                                                      |
   ! Version     Name        Date            Explanation of Changes       |
   ! ------- ------------ ----------- ----------------------------------- |
   !  0.00   Strauss      12 Oct 1993 Creation from PHTKSUM               |
   !  0.01   Strauss      06 Jan 1994 First Correct released version      |
   !  0.02   Homer        05 Mar 1994 added de/dx word                    |
   !  0.03   Richard      06 Oct 1994 change dE/dx to I*4                 |
   !*--------------------------------------------------------------------*/
 
   Bank PHCHRG Context=DST      DEMAND_ZERO Maxid=1000 "Useful tkpars/tk"
This is the template header which describes the bank. All templates must have headers. All but the last line of the header are enclosed in comment characters, however SLD's code management software needs to have this information. The information within the comment characters is as follows:

After the commented section of the header, we have the bank description line. It defines:

The DATA

The remainder of the template after the header defines the data structure. Each line defines a variable, showing first the type, then the name and then an (optional) description. Find HLXPAR

You should see a line that looks something like:

   REAL      HLXPAR(6)      "  *  track parameters and error matrix   * "
This tells us that HLXPAR is a real array of six elements. The "*" in the description tell us to look for the definition as a footnote. Somewhere near the bottom of the template you should find something that looks like:
   !  NOTE 3:
   !
   !     HLXPAR(1) = phi
   !     HLXPAR(2) = 1/pt
   !     HLXPAR(3) = tan(lambda)
   !     HLXPAR(4) = x
   !     HLXPAR(5) = y
   !     HLXPAR(6) = z
   !
   !     note: HLXPAR(4-6) are reported as (x,y,z) for convenience. the
   !     error matrix DHLXPAR(1-15) has elements which correspond to
   !     parameter 4 = TSI and parameter 5 = ETA, two distances to a
   !     given point defined by:
   !                       TSI =  TN dot DELTA
   !                       ETA =  TQ dot DELTA
   !
   !     where  DELTA = (x-x0, y-y0, z-z0)    {(x0,y0,z0) = given origin}
   !            TN    =  PHAT cross TM        (PHAT = momentum unit vector)
   !                                          (TM   = mag field unit vector)
   !            TQ    = (1/(1-(PHAT dot TM)**2) * (TM - (PHAT dot TM)PHAT)
   !
   !     to convert HLXPAR(1-3) to a momentum vector (PX,PY,PZ):
   !
   !            PTOT = pt/cos(lambda)
   !            PX   = PTOT * cos(lambda) * cos(phi)
   !            PY   = PTOT * cos(lambda) * sin(phi)
   !            PZ   = PTOT * sin(lambda)
So we see that HLXPAR(2) is the inverse transverse momentum. Now take a moment and study the rest of the data available in this bank.

Using and Manipulating banks

Now that we understand a little about the structure of a bank lets see what we can do with it. Start an Interactive Ida Session

To do this just type "IDA" at the VMS prompt. At the Ida prompt type:

   Ida>  Index 
You will get a list of banks currently in IDA memory. In the first column you will see the family name, in the second column the number of banks in this family, in the third column the context and in the fourth column a title or description. None of these are that interesting since they are Ida's default or automatically loaded banks. Add A PHCHRG bank to memory

To do this type:

   Ida> ADD PHCHRG
   Ida> INDEX
Now we see there is 1 PHCHRG bank in memory. Examine its contents.
   Ida>  PEEK PHCHRG
Note everything is Zero except ESTAT and MUSTAT. This makes sense since we are not looking at real data, all we did was load the bank into memory. There was a DEMAND ZERO at top of the PHCHRG template which clears all undeclared entries, but the values of estat and mustat where declared thus are non zero.

Setting Values inside a Bank

Lets set the impact parameter to 0.2 cm and the inverse transverse momentum to 0.1 1/GEV. To do this we look at the template and find that the variables we want are "IMPACT" and "HLXPAR(2)". We will use the POKE command which works like POKE BANK.VARIABLE=VALUE . So type:
   Ida>  POKE PHCHRG.IMPACT=0.2
   Ida>  POKE PHCHRG.HLXPAR(2)=0.1
   Ida>  PEEK PHCHRG
So we see that we were able to set the values of the bank element with the POKE command.

Let us now see how bank IDs come into play by adding another bank.

Add another PHCHRG bank as above:

 
   Ida>  ADD PHCHRG
   Ida>  INDEX
Note when we typed index we saw the number of PHCHRG banks was 2.
   Ida>  PEEK PHCHRG
Notice the top line says:
   Family: PHCHRG     ID:     2   Template Version: 0.00
So we examined the bank with ID=2, and we notice that HLXPAR(2) and IMPACT =0. The bank we changed the values in is ID = 1.
   Ida>  PEEK PHCHRG(1)
   Ida>  PEEK PHCHRG(2)
We see we can differentiate between the two banks by specifying the ID.

Using Pointers

So far we have just peeked into banks; we have not extracted any information in a way that we could actually fill into some other variable. In order to extract information we must define a POINTER, that is a variable that "points" to the location in memory of the bank in question. To do this type:
   Ida>  POINTER PC --> PHCHRG
Defines a pointer that points to the first bank in the family. We have the ability to set the pointer to point to whichever bank we desire. In order to do this, let us add one more bank and, for accounting purposes, let us set the charge equal to the bank ID.
   Ida>  ADD PHCHRG
   Ida>  POKE PHCHRG(1).CHARGE=1
   Ida>  POKE PHCHRG(2).CHARGE=2
   Ida>  POKE PHCHRG(3).CHARGE=3
Currently we have our pointer pointing at the first bank in the family. However we have the ability to change which bank the pointer points to. Now the way we reference a particular element is POINTER%(ELEMENT). We can display an element of a bank or a variable using the type command, which works like "TYPE VAR" or in our case "TYPE POINTER%(ELEMENT)".
   Ida>  TYPE PC%(charge)
   Ida>  PC=_PHCHRG(LAST)
   Ida>  TYPE PC%(charge)
   Ida>  PC=_PHCHRG(2)
   Ida>  TYPE PC%(charge)
   Ida>  PC=_PHCHRG
   Ida>  TYPE PC%(charge)
It is not always necessary to declare a pointer explicitly. The underscore notation "_BANK( )" is sufficient although sometimes making code harder for others to read. Using the underscore notation: Thus if one wanted to print an element of the first bank to the screen they could issue the command "TYPE _BANK%(ELEMENT).

Using Bankcnt and Bankloop

If we were working with real data, the number of charged tracks would change from event to event. Thus the number of PHCHRG banks would vary from event to event. In order to write effective code we must be able to count the banks and loop over them. To do this we use the bankcnt and bankloop commands.
   Ida>  TYPE BANKCNT(PC)
Note when using bankcnt we must have the pointer pointing to the first bank in the family. If it is not, it will only count the bank it is pointing at and the banks following that one. Therefore it is usually safer to use the command as follows.
   Ida>  TYPE BANKCNT(_PHCHRG)

If we wanted to loop over the banks we could do something like:

   Ida>  N=BANKCNT(_PHCHRG)
   Ida>  DO I = 1 TO N
   Ida>     PC=_PHCHRG(I)
   Ida>     TYPE PC%(CHARGE)
   Ida>  ENDDO
Note that after you type the do line you should see
   %IDA-I-INFO  Begin implicit definition

and ida does not do actually run the commands until you specify the end of the loop with the line "enddo." The format of an ida DO LOOP will be discussed in detail in a later section of this workbook.

Because so much of IDA code involves looping over banks, IDA has a special construction just for this purpose. You do not have to use it, the do loop construction shown above does work, but the "bankloop" construction is easier. The construction begins with "BANKLOOP FAMILY." Within the bankloop one can access an element with "BANK%(ELEMENT)" and bank will be incremented to point at the next ID each iteration. This eliminates the need for you to use and increment pointers.

To do the above loop using bankloop, type:

   Ida>  BANKLOOP PHCHRG
   Ida>     TYPE PHCHRG%(CHARGE)
   Ida>  END
We get the same result with less work.

Using Banks with Real Data

Up to now, this section of the Workbook has had you manipulating empty banks that you created yourself. Let us now apply what we have learned to real data.

At the Ida prompt type:

   Ida>  OPENTAPE READ REC94_MDST STAGE WAIT
   Ida>  GO 1
   Ida>  INDEX
   Ida>  TYPE BANKCNT(_PHCHRG)

Index shows us that we have many more types of banks in memory that we had before. Bankcnt tells us we have 15 PHCHRG banks representing 15 changed tracks found in this event. We also see this count of 15 by looking at the second column of the index output.

Plotting the Momentum Spectrum

In the first section of this workbook we made a plot of 1/pt. At that time we had to take a lot of things on faith. We should now be able to plot the full momentum spectrum and be abe to understand each of the steps. Remember PTOT = pt/cos(lambda), HLXPAR(2) = 1/pt and HLXPAR(3) = tan(lambda).

Note anything following "!" is just a comment no need for you to type. At the Ida prompt type:

   Ida> VAR PEVENT,PTOT,LAMBDA,PT  !declare variables
   Ida>  DEF EVANAL               !define event analysis
   Ida>  BANKLOOP PHCHRG          !loop over all phchrg banks in event.
   Ida>  LAMBDA = ATAN(PHCHRG%(HLXPAR(3))) !get angle lambda
   Ida>  PT=1/PHCHRG%(HLXPAR(2))           !get pt 
   Ida>  PTOT=PT/COS(LAMBDA)               !define Ptot
   Ida> HIST PTOT FROM 0 TO 50 ID 10 TITLE "MOMENTUM PER TRACK"
   Ida> PEVENT=PTOT+PEVENT
   Ida> END                      !End loop ever phchrg banks
   Ida> HIST PEVENT FROM 0 TO 100 ID 20 TITLE "MOMENTUM PER EVENT"
   Ida> PEVENT=0                 !clear PEVENT for next event
   Ida> ENDDEF                   !end event loop
   Ida> go 100                   !Do 100 events
   Ida> HOUT 10 SDDXWDO          !Display histogram
   Ida> HOUT 20 SDDXWDO          !Display histogram

Using Banks With Data Blocks

We have seen that Jazelle banks can contain 1 dimensional arrays such as
   REAL      HLXPAR(6)      "  *  track parameters and error matrix   * "
Unfortunately multiple dimensions on one variable are not allowed, e.g. Real D(10,10) is illegal. However there is a way around this problem using Data Blocks.

Data blocks are particularly useful when it is desirable to group a set of variables together logical, especially when you desire to repeat a set of variables a number of times. Blocks may occur anywhere within a bank including within other blocks. Blocks also provide a means of creating multiple dimension arrays. Again it is easier to learn by example. So lets look at the PHKLUS bank which contains information about calorimetry clusters. There should be one bank per cluster. Get a copy of PHKLUS.TEMPLATE in your editor.

You can do this by typing:

   > eve ducssearch:phklus.template

Search through the file until you find

   Block LAYER(2:3)    "Layer by layer info EM section"

     Integer   NHIT    "Number of towers hit"

     Real      CTH     "Mean cluster cos(theta) this layer (energy weighted)"
     Real      WCTH    "Width of energy in cos(theta)"
     Real      PHI     "Mean cluster phi in this layer (energy weighted)"
     Real      WPHI    "Width of energy in phi"

   Endblock

Here we see a block named "LAYER" representing the EM1 and EM2 sections of the LAC (Liquid Argon Calorimeter). For each layer the block contains the number of towers hit, the mean cos theta of cluster, the width of the cluster, the mean phi of cluster and the width in phi. Accessing information stored in a block is very similar to accessing a regular variable the form is POINTER%(BLOCK(NUMBER),VARIABLE). So the number of towers hit in EM1 of the first bank/cluster of a given event would be _PHKLUS%(LAYER(2),NHIT).

Let us plot the energy per layer vs costh of the cluster. Note in SLD Kalorimeter Coordinates layers 0-7 correspond to:

So we will be concerned with layers 2 and 3 in the following example. If you do not still have an ida session going start one up and open the same data set as above. Then at the ida prompt.

Note a line ending with a "-" tells ida the command is continued on the next line.

                  
   Ida>  DEF EVANAL           !Define event loop
   Ida>    BANKLOOP PHKLUS
   Ida>      EEM1=PHKLUS%(ELAYER(2))
   Ida>      CTEM1=PHKLUS%(LAYER(2),CTH)
   Ida>      EEM2=PHKLUS%(ELAYER(3))
   Ida>      CTEM2=PHKLUS%(LAYER(3),CTH)
   Ida>      SCAT EEM1 FROM 0 TO 40 VS CTEM1 FROM -1 TO 1 -
   Ida>      ID 30 TITLE "EM1 COSTH ENERGY DISTRIBUTION"
   Ida>      SCAT EEM2 FROM 0 TO 40 VS CTEM2 FROM -1 TO 1 -
   Ida>      ID 40 TITLE "EM2 COSTH ENERGY DISTRIBUTION"
   Ida>    END
   Ida>  ENDDEF
   Ida>  GO 300
   Ida>  HOUT 30 SDDXWDO
   Ida>  HOUT 40 SDDXWDO

As mentioned earlier we can have blocks inside blocks for instance if we wanted to store all the clusters in one bank we could have something like.

Note the following is a fictitious bank created as an example for this exercise.

   Bank Klusall context=fictitious Maxid=1 "fictitious bank for illustration"

   INTEGER NKLUS                      !number of clusters

   BLOCK CLUST(NKLUS)                 !cluster by cluster info section
 
      Real    ERAW      "Raw cluster energy (before e/pi correction)"
      Real    CTH       "Mean cluster cos(theta) (energy weighted)"
      Real    WCTH      "Width of cluster in cos(theta)"

      Real    PHI       "Mean cluster phi (energy weighted)"
      Real    WPHI      "Width of cluster in phi"

      Real Elayer(0:7)  "energy by layer (MIP scale)"

      Block LAYER(2:3)    "Layer by layer info EM section"

        Integer   NHIT    "Number of towers hit"

        Real      CTH     "Mean cluster cos(theta) this layer (energy weighted)"
        Real      WCTH    "Width of energy in cos(theta)"
        Real      PHI     "Mean cluster phi in this layer (energy weighted)"
        Real      WPHI    "Width of energy in phi"

      Endblock
   Endblock
Now if one wanted to find Costh in Lac Em1 of the third cluster it would be:

_KLUSALL%(CLUST(3),LAYER(2),CTH)

This section was designed to give you a basic working understanding of Jazelle banks. By no means did we cover all the intricacies of Jazelle. However I hope things are a little less mysterious now. At some point when you are done with this workbook and have a little more experience working with banks you may want to read the official Jazelle Manual.


Back to Main Data Page

Eric Weiss
13 January 1995