ADAMO for beginners


Robert Hatcher

A tutorial based on my talk given on June 13, 1997
at the MINOS Week-in-the-woods (Ely, MN)


Table of Context

Introduction

The ADAMO package provides the framework for the MINOS data structures. In addition it is a mechanism for memory management under fortran77. ADAMO hides the complexity of ZEBRA/BOS by providing a super-layer interface. This imposes limitations on the possible structures, but has the compensating feature of portably and reliably handling the evolution of the structures.

The definitive location for information on ADAMO is the URL maintained at CERN by the Information and Programming Technology Group: http://www1.cern.ch/Adamo/ADAMO_ENTRY.html

Features of ADAMO

ADAMO implements a Entity-Relationship data model.

Advantages of ADAMO:

As well a handling the structures internally in memory, ADAMO also supplies routines for input/output via the Generic ADAMO File (GAF):

A simplistic guide to ADAMO terminology

.ddl file
The .ddl file rigorously defines the structure of the data in a computer (and human) readable format (Data Definition Language). As well as describing the data model it also specifies types, validity ranges, relationships and provides additional documentation in the form of comments associated with the attributes.
ESet
An entity set (ESet) is a set of "objects" with identical structures. The entity is expressed by a group of attributes each carrying a value. In ADAMO, an ESet is mapped into a table format where each attribute constitutes a column and a complete entity is the collection values in a single row.
(attribute,value) pairs
An attribute might otherwise be called a "tag"; in fortran it would be the variable name. Each attribute takes on some range of values. ADAMO pre-defines a number of types for attributes, such as REAL (all standard floating point values), INTE (legal integers), CHA4 (four character strings). In setting up a list of attributes the user picks an appropriate type. These can be further constrained, eg. INTE [1,100] would restrict the attribute to integers between one and one hundred, inclusive.
RSet
A relationship set connects entries in one ESet to those of another. This link can be partial (on either or both ends), in that not all members of one or both ESets have such a link connecting them to the other ESet. In ADAMO the relationship can at most be 1:1 or n:1, never n:m. In the first case, any relationship connects, at most, one entity from the first ESet to any given member of the second ESet. The n:1 case allows any number of members of the first set to point at the same entity in the second. What isn't allowed is for members of the first ESet to point to multiple members of the second ESet. This restriction can be overcome by setting up an intermediate ESet if necessary.
Dataflow
A dataflow groups together logically related ESets. Typically this would be a group of tables that would be collectively written to a file simultaneously as a logical record.
GAF file
A gaf (Generic Adamo File) is the actual file written or read by ADAMO. Internally there are different file formats and they must be read by the same driver used in writing them. Zebra FZ exchange format files will generally have the file name extension .fz_gaf, while ASCII text files use .ie_gaf.
Window common
An include file bearing the name of the data structure. The common provides the means for accessing one row (one entity) of an ESet in Fortran77. The declared common contains the internal reference for the table and a fortran variable for each attribute (and relationship link).
Table index
An index is an ordered list of all the IDs of a table. Tables are not reordered in memory but are simply accessed via an index: the order of the IDs in the index is such that the entities are sorted according to the values of one or more attributes. Tables may have several indices, specifying different ways of ordering rows. from the ADAMO Users Guide

The term cursor is often used in association with indices. Cursors delimit a range of rows in a table as ordered along a particular index.

Example: subset of a .ddl file

The following is an extracted subset of the geom.ddl file. Every .ddl file describes a subschema. There are four major parts to each subschema: header information, the definition of attribute types, declarations of ESets, declaration of RSets (relationships).

The ADAMO user under fortran77 does not directly see any specially designed attribute types. All are mapped to standard types such as real, integer, character; restrictions on the ranges are managed internally by ADAMO and may trigger warning messages during validity checks.

The definition of a ESet (in our case PlanePos and partially PlaneSpec) describes the contents of each entity in the set. A list of attributes with accompanying types (and range) and descriptions are collected together as a unit.

The relationships are defined in the RSet section. These describe which tables are related and by what name. These entries also document the connectivity: whether a relationship is required for each source table; and whether more than one source entity can link to the same destination entry.


SUBSCHEMA MINOSGeom : 'Detector configuration'

  AUTHOR     'Robert Hatcher'
  VERSION    '1.0'
  DATE       '1996.05.24'
  REVIEWER   ' '

  DEFINE ATTRIBUTE

    GlobalPos = REAL                      :'global co-ordinate';
    ShapeName = CHA4 'BOX '|'TUBE'|'PGON' 
                                    :'restricted list of GEANT shapes';  
  END ATTRIBUTE

  DEFINE ESET

   PlanePos =
     ( ISuper      = INTE [1,15]  : 'supermodule number',
       IModule     = INTE [1,300] : 'module number',
       InMdl       = INTE [1,16]  : 'pasv/actv plane pair in module',
       PairZmin    = GlobalPos    : 'upstream extent of pair',
       PairZmax    = GlobalPos    : 'downstream extent (including air gap)',
       PasvName    = CHA4         : 'name of passive plane',
       XYPasv(2)   = GlobalPos    : 'X/Y (cm) center of passive plane',
       ZFrntPasv   = GlobalPos    : 'Z (cm) front face of passive plane',
       ActvName    = CHA4         : 'name of active plane',
       XYActv(2)   = GlobalPos    : 'X/Y (cm) center of active plane',
       ZFrntActv   = GlobalPos    : 'Z (cm) front face of active plane',
       Rotm        = CHA4         : 'rotation of active plane'
     );

   PlaneSpec =
     ( PlnName     = CHA4        : 'plane name (ie. key,instance,PL)',
       Shape       = ShapeName   : 'GEANT shape name',
       Width       = REAL        : 'face-to-face width of plane (cm)',
       Thickness   = REAL        : 'z thickness of plane (cm)',
       ....
     ); 

  END ESET

  DEFINE RSET
   (PlanePos [1,1] -> [1,*] PlaneSpec BY PasvSpec)
      : 'point to the PlaneSpec for the Passive plane of pair';

   (PlanePos [1,1] -> [1,*] PlaneSpec BY ActvSpec)
      : 'point to the PlaneSpec for the Active plane of pair';
  END RSET

END SUBSCHEMA

Example: a table listing

If one were to use the ADAMO function for printing out the contents of the filled PlanePos table it would look similar to the following. This example has been truncated to the first four entries.

This example table is both too long and too wide for a normal screen so ADAMO attempts to format it by first grouping by ranges of roughly 50 rows, and then splitting the width into groups of attributes that will fit into 80 columns. ADAMO routines provide a means of tweaking the formatting (without actually affecting the underlying data). By displaying the information this way the imposed tabular format becomes quite apparent.

 |-------------------------------------------------------------------|
 | Table: PlanePos                                         ADAMO/TAP |
 | Count:  600                                                       |
 | Page (  1,  1)                                                    |
 | Printed along:  ID [MINC,MAXC]                                    |
 |-------------------------------------------------------------------|
 |ID  |IS|IMo|In|PairZmin|PairZmax|Pasv|XYPasv(1)|(2)      |ZFrntPasv|
 |----|--|---|--|--------|--------|----|---------|---------|---------|
 |   1| 1|  1| 1| 250.000| 257.060|B1PL| .000E+00| .000E+00| 250.200 !
 |   2| 1|  1| 2| 257.060| 264.120|B1PL| .000E+00| .000E+00| 257.260 !
 |   3| 1|  1| 3| 264.120| 271.180|B1PL| .000E+00| .000E+00| 264.320 !
 |   4| 1|  1| 4| 271.180| 278.240|B1PL| .000E+00| .000E+00| 271.380 !



 |--------------------------------------------------------------|
 | Table: PlanePos                                              |
 | Page (  2,  1)                                               |
 |--------------------------------------------------------------|
 |ID  |Actv|XYActv(1)|(2)      |ZFrntActv|Rotm#ActvSpec|PasvSpec|
 |----|----|---------|---------|---------|----#--------|--------|
 |   1|F1PL| .000E+00| .000E+00| 254.600 |U   #       2|       1|
 |   2|F1PL| .000E+00| .000E+00| 261.660 |V   #       2|       1|
 |   3|F1PL| .000E+00| .000E+00| 268.720 |U   #       2|       1|
 |   4|F1PL| .000E+00| .000E+00| 275.780 |V   #       2|       1|

Example: window common

The ESet and RSet information in the .ddl file is processed by the mad program into include files containing the window common blocks. This process is a normal part of building the MINOS code library. Users should never directly modify these files, but instead changes to the structures must be reflected in the .ddl file proper.

The filename and common exactly match the name of the ESet, including case. The first variable also matches the name of the ESet and will automatically be filled by ADAMO with an internal reference that it will use to reference the table; this token is then passed by the user to various ADAMO routines. Do not modify the value in that variable or be prepared to face the dire consequences (e.g. filling your disk with error messages). The variable ending with 9999 is a fence to catch attempts to write beyond the end of the common.

      INTEGER     PlanePos, PlanePos_9999
      INTEGER     PlanePos_ID,
     +            PlanePos_ISuper, PlanePos_IModule, PlanePos_InMdl,
     +            PlanePos_ActvSpec, PlanePos_PasvSpec
      CHARACTER*4 PlanePos_PasvName, PlanePos_ActvName, PlanePos_Rotm
      REAL        PlanePos_PairZmin, PlanePos_PairZmax,
     +            PlanePos_XYPasv, PlanePos_ZFrntPasv,
     +            PlanePos_XYActv, PlanePos_ZFrntActv

      COMMON /PlanePos/ PlanePos, PlanePos_ID,
     +   PlanePos_ISuper, PlanePos_IModule, PlanePos_InMdl,
     +   PlanePos_PairZmin, PlanePos_PairZmax,
     +   PlanePos_PasvName, PlanePos_XYPasv(2), PlanePos_ZFrntPasv,
     +   PlanePos_ActvName, PlanePos_XYActv(2), PlanePos_ZFrntActv,
     +   PlanePos_Rotm, PlanePos_ActvSpec, PlanePos_PasvSpec,
     +   PlanePos_9999

TIP = PAW + ADAMO

The TIP program is built when ADAMO is built and so should be available at all sites. It provides a means to interactively deal with ADAMO structures. There are lots of capabilities built in, but generally I tend to use it for perusing a GAF file.

Here's a KUMAC file for opening the GAF file and reading in the first event:


macro read_gaf 1=minos_events.fz_gaf

*- decompose the filename
filename = [1]
ndot = $WORDS([filename],'.')
extension = $WORD([filename],[ndot],1,'.')
message filename [filename] extension [extension]

*- attempt close in case of previous open
gaf/close mygaf

*- open the file, use appropriate driver
case [extension] in
  (fz_gaf) gaf/open mygaf NAME=[filename],DRIVER=FZ,filfor=EXCH,recfor=EXCH
  (ie_gaf) gaf/open mygaf NAME=[filename],DRIVER=IE
  (*)      message read_gaf.kumac: Unknown file extension [extension]
           message read_gaf.kumac: Attempt to open with FZ driver
           gaf/open mygaf NAME=[filename],DRIVER=FZ,filfor=EXCH,recfor=EXCH
endcase

*- read geometry tables (first entry in gaf)
gaf/next mygaf
gaf/accept mygaf

*- read an event dataflow
gaf/next mygaf
gaf/accept mygaf

return

The macro assume the file name includes the extension and attempts to use the right driver based on it. Under tip execute a command similar to:
  TIP> exec read_gaf gminos_22110_1.fz_gaf
You can dump individual tables using commands like:
  TIP> table/print all FLSDigit
where FLSDigit is an example ESet. I recommend people take a look at PlanePos and PlaneSpec to get an idea of the structures.

The pair of commands

gaf/next mygaf
gaf/accept mygaf
will read in the next event.

Example session

TIP is started from the normal user shell; commands are entered at the TIP> prompt.
$ tip
 !--------------------------------------------------------
 !ADAMO/TIP : Table Interaction and Plotting = ADAMO + PAW
 !--------------------------------------------------------
 ******************************************************
 *                                                    *
 *            W E L C O M E    to   P A W             *
 *                                                    *
 *       Version 2.04/15      14 March 1994           *
 *                                                    *
 ******************************************************
 Workstation type (?=HELP) <CR>=1 :
 Version 1.20/11 of HIGZ started
 *** Using default PAWLOGON file "/user4/hatcher/.pawlogon.kumac"

  PAW Logon

 ADAMO/TAP version 3.3      with GAF version 3.2      starting

 ORACLE Driver added

 ... try to execute your TIP kumac file ...
 *** Unknown file tip.kumac

 Enter HELP TIP for help

TIP> exec read_gaf minos_events_r11101.fz_gaf
 File not yet opened by you
 Record found: MinosGeom
 Type            : GEOM
 Version         : 1
 RunNo           : 11101
 EventNo         : 0
 Record found: GeantEvent
 Type            : GEVT
 Version         : 1
 RunNo           : 11101
 EventNo         : 1
TIP> table/list
 |-----------------------------------------------------------|
 | Page (  1,  1)                                            |
 |-----------------------------------------------------------|
 |Name            |ID  |Count|LaSeN|IniCr|MaxCr|Open|Division|
 |----------------|----|-----|-----|-----|-----|----|--------|
 |BeamSystem      |  43|    1|    1|=====|=====|   T| 4000002|
 |CellPos         |  36|  776|  776|=====|=====|   T| 4000002|
 |DigitPln        |  44|    0|    0|=====|=====|   T| 4000002|
 |FLSDigit        |  45|    0|    0|=====|=====|   T| 4000002|
 |FLSHit          |  46|    0|    0|=====|=====|   T| 4000002|
 |GeomMisc        |  37|    1|    1|=====|=====|   T| 4000002|
 |HitPln          |  47|   29|   29|=====|=====|   T| 4000002|
 |LSTHit          |  48|  245|  245|=====|=====|   T| 4000002|
 |LSTProto        |  49|    0|    0|=====|=====|   T| 4000002|
 |LSTStrip        |  50|    0|    0|=====|=====|   T| 4000002|
 |LSTWire         |  51|    0|    0|=====|=====|   T| 4000002|
 |Material        |  31|   32|  101|=====|=====|   T| 4000002|
 |MdlOrg          |  38|   24|   24|=====|=====|   T| 4000002|
 |Mixture         |  32|   63|   63|=====|=====|   T| 4000002|
 |NeuKin          |  52|    1|    1|=====|=====|   T| 4000002|
 |NeuVtx          |  53|    1|    1|=====|=====|   T| 4000002|
 |PlanePos        |  39|  600|  600|=====|=====|   T| 4000002|
 |PlaneSpec       |  40|    2|    2|=====|=====|   T| 4000002|
 |Rotm            |  33|    6|  301|=====|=====|   T| 4000002|
 |StdHep          |  54|   31|   31|=====|=====|   T| 4000002|
 |StdHepHead      |  55|    1|    1|=====|=====|   T| 4000002|
 |SubVolSpec      |  41|    0|    0|=====|=====|   T| 4000002|
 |SuperModule     |  42|    3|    3|=====|=====|   T| 4000002|
 |TMedium         |  34|   33|  101|=====|=====|   T| 4000002|
 |TPar            |  35|    1|    1|=====|=====|   T| 4000002|
 |-----------------------------------------------------------|
TIP> gaf/next mygaf
 Record found: GeantEvent
 Type            : GEVT
 Version         : 1
 RunNo           : 11101
 EventNo         : 2
TIP> gaf/accept mygaf
TIP> table/print all StdHep
 |----------------------------------------------------------------------------|
 | Table: StdHep                                                    ADAMO/TAP |
 | Count:  6                                                                  |
 | Page (  1,  1)                                                             |
 | Printed along:  ID [MINC,MAXC]                                             |
 |----------------------------------------------------------------------------|
 |ID  |Ist|IdHEP |Jmo|(2)|Jda|(2)|PHEP(1) |(2)     |(3)     |(4)     |(5)     |
 |----|---|------|---|---|---|---|--------|--------|--------|--------|--------|
 |   1|  3|    14|  0|  0|  0|  0|    .000|    .326|   5.616|   5.625|    .000|
 |   2|  3|******|  0|  0|  0|  0|    .000|    .000|    .000|  52.103|  52.103|
 |   3|  3|  2112|  0|  0|  0|  0|    .074|    .202|   -.058|    .931|    .904|
 |   4|  0|******|  0|  0|  0|  0|   -.074|   -.202|    .058|  51.172|  51.172|
 |   5|  0|    13|  0|  0|  0|  0|    .060|   1.120|   5.299|   5.417|    .106|
 |   6|  0|  2212|  0|  0|  0|  0|    .014|   -.592|    .259|   1.139|    .938|
 |----------------------------------------------------------------------------|
 |-------------------------------------------|
 | Table: StdHep                             |
 | Page (  2,  1)                            |
 |-------------------------------------------|
 |ID  |VHEP(1) |(2)     |(3)     |(4)     |  |
 |----|--------|--------|--------|--------|  |
 |   1|   -76.6|  2600.7| 38691.7|      .0|  |
 |   2|   -76.6|  2600.7| 38691.7|      .0|  |
 |   3|   -76.6|  2600.7| 38691.7|      .0|  |
 |   4|   -76.6|  2600.7| 38691.7|      .0|  |
 |   5|   -76.6|  2600.7| 38691.7|      .0|  |
 |   6|   -76.6|  2600.7| 38691.7|      .0|  |
 |-------------------------------------------|
TIP> quit
 TIP closing down ...
 ... done.
 Exiting from PAW.

Selected ADAMO functions

This section is a condensed list of many of the commonly used functions of ADAMO. The definitive location for information on ADAMO is the URL maintained at CERN by the Information and Programming Technology Group: http://www1.cern.ch/Adamo/ADAMO_ENTRY.html. User and Reference guides can be found at that location.

Conventions:

When this document is viewed via a web browser, color will help differentiate the components:
ADAMO subroutine/function
partap.inc constant
window common variable
table attribute (column)

All references to particular tables (eg. FLSDigit, PlanePos, PlaneSpec, RecoVtx) are simply for illustration purposes.

Including the window commons:

#include "FLSDigit.inc"
#include "PlanePos.inc"
#include "PlaneSpec.inc"
#include "RecoVtx.inc"
#include "partap.inc"
The first four lines make the window common for various tables available to the current routine. The partap.inc include file declares the type of ADAMO functions and defines some special values used in ADAMO interactions. A complete list of the variable names to avoid are:
ALL ALLCOL AND CANY CNULL DIF HOR IANY ID INS INULL
KEE MAXC MINC NEXT OR ORD RANY REP RNULL UNO VER

Print the whole table:

A formatted listing of a complete table can be generated using:
      call PRITAB(FLSDigit,ID,MINC,MAXC,ALLCOL)

Count the number of rows:

The actual number of rows in a table is given by:
      ndigit = COUTAB(FLSDigit)
Note that this need not be the same as the highest row number (ie. the largest value of FLSDigit_ID).

Retrieve one row of a table:

There are two methods, the first is marginally faster while the second is more general.
      FLSDigit_ID = idigit
      call GETTAB(FLSDigit)

      call FETTAB(FLSDigit,ID,idigit)

Tables are automatically ordered along every attribute (ie. column), of which ID is only one index. For example, to loop over all the entries in the FLSDigit table from the lowest value in the ADC(1) attribute to the highest one can write code similar to:

      integer indx_adc1
      indx_adc1 = GETIND(FLSDigit,'ADC(1)')
      do idigit = 1, ndigit
         call FETTAB(FLSDigit,indx_adc1,idigit)
Remember, ndigit is the number of entries in the table and is returned by the COUTAB function. The indx_adc1 variable carries the internal information that ADAMO needs to determine which ordering to use; the partap constant ID is but a special value defined for all tables.

While at first the two methods seem to give identical results when FETTAB is called with the ID index, the difference is not simply in the syntax. The two parallel each other if-and-only-if the table is filled consecutively from ID=1 with no gaps. In the case of GETTAB one is retrieving the row with ID = idigit, while for FETTAB one gets the idigit-th entry in the table, independent of the actual row number (eg. ID). Thus if the possibility exists that entries in the table might be deleted, it is better to use FETTAB to perform loops. Such a loop from 1 to COUTAB will access each available row. On the other hand, for a table with gaps in the row numbers the loop

      ndigit = COUTAB(FLSDigit)
      do idigit = 1, ndigit
         FLSDigit_ID = idigit
         call GETTAB(FLSDigit)
      enddo
will fail to span all the available rows and will attempt to access rows that do not exist. Such accesses generate messages such as:
 !ADAMO/TAP/GETTAB/Run-time error  Table                : FLSDigit
 !                                 Row                  : 99
 !-------------------------------> Row does not exist

Multi-attribute ordering:

ADAMO can also order over multiple attributes to resolve ambiguities. For instance, if one wishes to loop over all entries in FLSDigit such that it is ordered by plane number, extrusion number, cell number (with adjacent cells in the same extrusion/plane consecutive), one can construct an index (here named indx_fls_pec). The 'ASC' indicates ascending ordering; the alternative is 'DESC'.

      integer indx_fls_pec
      character*16 attnam(3)
      character*4 order(3)

      attnam(1) = 'IPln'
      attnam(2) = 'IExtr'
      attnam(3) = 'ICell'
      order(1)  = 'ASC'
      order(2)  = 'ASC'
      order(3)  = 'ASC'
      call CREIND(FLSDigit,indx_fls_pec,'INDX_FLS_PEC',3,attnam,order)

      do idigit = 1, ndigit
         call FETTAB(FLSDigit,indx_fls_pec,idigit)
It is recommended that users not use the name index for holding the values from CREIND or GETIND; index is the name of a standard fortran language string function. The user declaration with override the default, but it will also generate compiler warning messages and lead to reader confusion.

Created table indices are persistent. This means that the ordering is maintained even if rows are added or deleted or the table is cleared and and re-filled (ie. by the next event). One can remove user defined orderings with the command:

      call DROIND(FLSDigit,'INDX_FLS_PEC')
where 'INDX_FLS_PEC' matches the label used in creating the index. Thus a routine should either have a matching DROIND for every CREIND, or the CREIND should only be called once.

The indx_fls_pec variable holds a "handle" identifying the index. Users must be careful to either use the fortran SAVE statement to ensure that the value is static across invocations of the subroutine, or they should use

      indx_fls_pec = GETIND(FLSDigit,'INDX_FLS_PEC')
to restore the value each time the subroutine is called. Without a statement similar to SAVE indx_fls_pec, this local variable will be put on the heap or stack and its value is not guaranteed to be retained after exiting the subroutine.

Select matches on an attributes:

ADAMO has some powerful routines for selecting sub-sets of a table. For instance, if one wished to loop over digitizations in one specific plane the code would look like:
      integer indx_ipln, klo, khi, k
      indx_ipln = GETIND(FLSDigit,'IPln')
      FLSDigit_IPln = my_plane
      call SELTAB(FLSDigit,indx_ipln,klo,khi)
      do k = klo, khi
         call FETTAB(FLSDigit,indx_ipln,k)
The klo, khi variables are referred to as cursors; they delimit a range when the table is viewed as ordered along a particular index. Be aware that cursors are not transferrable to other indices. They are only meaningful for the index used in the SELTAB call.

If the index used in the SELTAB call involves more than one attribute, then the user should set all the relevant values in the window common before the SELTAB call.

Caveats: the ordering index in SELTAB and FETTAB must be the same; the retrieved order of digitizations within a plane is undefined. One is guarenteed to loop over all that match the criteria, but the ambiguity of ordering is resolved by the ID attribute, and so it depends on how they were entered into the table. The technique demonstrated in the next sub-section could be used in conjuction with the a user-created multi-attribute ordering to get the exact sequence desired.

Select range of an attributes:

Even when the SELTAB call finds no exact matches it still returns important information. The cursors klo and khi are defined so that loops over exact matches follow a natural form. The cursors also partition the table. If there was no exact match (as is often the case for non-integer real numbers) then klo is the first row with a higher value, and khi is the last row with a lower value. Thus with two calls to SELTAB one can select for a range on an attribute.

The code fragment:

      FLSDigit_ADC(1) = 2.3
      call SELTAB(FLSDigit,indx_adc1,klo1,khi1)
c klo1 contains the next row with a value > 2.3

      FLSDigit_ADC(1) = 5.6
      call SELTAB(FLSDigit,indx_adc1,klo2,khi2)
c khi2 contains the last row with a value < 5.6

      do k = klo1, khi2
         call FETTAB(FLSDigit,indx_ipln,k)
loops over all digitizations with ADC(1) in the range [2.3,5.6].

Note than one can also use these cursors to print a range of a table:

      call PRITAB(FLSDigit,indx_adc1,klo1,khi2,ALLCOL)

Follow a relationship:

Each plane who's position and orientation is described in the PlanePos table is an specific instance of a more generic plane. The parameters of the plane's geometry (eg. width, thickness, material type...) can be found in the PlaneSpec table. There is a relationship that ties these together.

Actually, each entry in the PlanePos table represents information about two planes, the active detector plane and the passive absorber immediately upstream (towards the neutrino source). In most cases the absorber plane is the iron magnet plane, but in the case of a geometry that involves two active detectors for every iron plane a thin sheet of "air" is inserted between the two.

To determine the properties of a plane one needs to follow the relationship

      logical ok
      real zfront, zback

c find the front and back z position of passive plane "ipln"
      call FETTAB(PlanePos,ID,ipln)
      call NATREL(PlanePos,PlanePos_PasvSpec,PlaneSpec,ok)
c if ok=.true. then the PlaneSpec window contains the information about
c the absorber plane
      zfront = PlanePos_ZFrntPasv
      zback  = zfront + PlaneSpec_Thickness

c find the front and back z position of active plane "ipln"
      call FETTAB(PlanePos,ID,ipln)
      call NATREL(PlanePos,PlanePos_ActvSpec,PlaneSpec,ok)
c if ok=.true. then the PlaneSpec window contains the information about
c the active detector plane
      zfront = PlanePos_ZFrntActv
      zback  = zfront + PlaneSpec_Thickness

Clear window variables:

ADAMO can set all the variables in a window common to special values that it uses to represent an "unset" condition. This is useful to ensuring that values are not carried over from old values. This is important when preparing to make a new row entry. The call:
      call NULWIN(RecoVtx)
sets all the integer variables to INULL, the real variables to RNULL, and the character variables to CNULL. These values are parameterized in the include file partap.inc.

Insert a new row:

To make a new row in the table one fills up the window common with the desired values and then calls INSTAB. It is wise to call NULWIN before starting to fill the window; this ensures that no values are accidentally carried over. The table_ID variable represents the row number. Normally this should be set to the special value NEXT to represent the next available slot after the current entries -- this is preferable to picking a specific row number which should be avoided except under very pressing reasons.
      
      call NULWIN(RecoVtx)
      RecoVtx_ID      = NEXT
      RecoVtx_X       = x_guess
      ...             = ...
      RecoVtx_IPln    = ipln_vtx_guess
      RecoVtx_Routine = 'my vertex finder'
      call INSTAB(RecoVtx)

Modify an existing row:

When making a modification to a row, do not modify the table_ID variable.
      call FETTAB(RecoVtx,ID,i)
      RecoVtx_Routine = 'xyzzy'
      call REPTAB(RecoVtx)

Clear a whole table:

Clearing a whole table is easy.
      call CLETAB(LSTStrip)
Be sure that is really what you want to do. This should not be done to general Reco tables by individual reconstruction algorithms (though it is okay for tables specific to an algorithm). In general, the Reco tables should be a place to accumulate results for a variety of alternative algorithms and no one routine should wipe the table. In the reco_minos framework all such tables should get cleared in the routine clear_reco which is called before the user hook reco_event.

Remove a single row:

Deleting a single row is in principle easy. In practice one must be careful of two potential stumbling blocks.
      FLSDigit_ID = idigit
      call DELTAB(FLSDigit)
      call CLENXT(FLSDigit)
The CLENXT call ensures that the internal state of the table is consistent; this means that the counter containing maximum number entries is updated, and future calls to INSTAB with the *_ID = NEXT correctly adds to the end of the table.

One must also be careful when deleting rows from within a loop. This must be done while looping backwards so as not to upset the loop.

      do idigit = COUTAB(FLSDigit), 1, -1
         call FETTAB(FLSDigit,ID,idigit)
         if (FLSDigit_ADC(1) .lt. 3.0) call DELTAB(FLSDigit)
      enddo
      call CLENXT(FLSDigit)
Removing multiple rows with a common property can be more easily accomplished using the DEMTAB routine.

Remove a range of rows:

Given a range of rows in a table ordered along a particular index one can delete them with the DEMTAB call, as in:
      FLSDigit_IPln = my_plane
      call SELTAB(FLSDigit,indx_ipln,klo,khi)
      call DEMTAB(FLSDigit,indx_ipln,klo,khi)
      call CLENXT(FLSDigit)
Again, it is wise to follow up deletions with a call to CLENXT in anticipation of future INSTAB calls.

Robert Hatcher <hatcher@astro.indiana.edu>
Last modified: Tue Jun 24 16:40:30 1997