Documentation on Adam Hincks' Summer 2003 Software

Adam Hincks
2 September 2003


Contents

  1. Introduction
    1. Overview
    2. Files & Directories
  2. SPlot
    1. Description
    2. Practical Information
  3. Runfile Class
    1. Description
    2. Public Functions
    3. Defined Constants
    4. Practical Information
    5. Example
  4. Plotting & Graphics Classes
    1. Overview
    2. Practical Information
    3. Plotdata Class
      1. Description
      2. Public Functions
    4. Gnuplot Class
      1. Description
      2. Public Functions
      3. Defined Constants
    5. Plotting + Gnuplot Example
    6. G2Wrapper Class
      1. Description
      2. Public Functions
      3. Defined Constants
      4. Example
  5. Process Class
    1. Overview
    2. Directory Structure and File Formats
    3. Algorithms
    4. Public Functions
    5. Practical Information
    6. Example
  6. Utility Classes & Functions
    1. Miscellaneous Functions & Structures
    2. Histogram Class
      1. Description
      2. Public Functions
    3. Hitchans Class
      1. Description
      2. Public Functions
    4. Practical Information
    5. Example
  7. Monitoring Programme
    1. Running the Monitor
    2. What is Displayed
    3. Changing Settings
  8. Pulse Plotting Programme
    1. Overview
    2. Creating Configuration Files
    3. Running PPlot
  9. Other Programmes
  10. Appendix
    1. Petr Gorbunov's Libraries
    2. Gnuplot
    3. Gnuplot_i Library
    4. G2 Library
    5. PsJoin
    6. Quicksort algorithm




1.2     Introduction


1.1     Overview

The code I wrote over the summer can be roughly divided into two: splot, and the smaller, more modular code written after it.

Splot turned into an all-in-one programme for plotting pulse shapes and performing basic analysis on FCal data soon after been collected. It was useful for quickly displaying plots using gnuplot. Much of it was written in an ad hoc way, to analyse a particular problem. In this way it is rather restrictive as it is more a set of specific tools than a versatile analysis package.

Towards the middle of the test-beam run, splot was becoming frustratingly clunky and difficult to modify because it was a single programme performing many different tasks. It was at this stage that I began writing sets of C++ classes that could be used to write concise, customised programmes for analysing the testbeam data. These classes recycle much of the code from splot.

The runfile class unpacks data from the run files and can be accessed for the raw data. It is designed in such a way that a programme using it can access raw data without knowing anything about the actual data structure of the run files.

The plotdata and gnuplot classes are used to display plots in gnuplot. They can be used independently of any of the other classes I wrote. The g2wrapper class is used to draw graphics primitives in a window.

The process class is designed to sit on top of the runfile class and process the raw data. It subtracts pedestals and multiplies by the correct gain, and can provide information on the timing of a pulse.

There is also a file of utilities (utils) which provides functions and classes for useful, often repeated tasks, such as passing a parabola through three points, or filling a histogram.

Each of the classes included in this help file has an example file. Studied in order, they should provide instructive, and in themselves are useful tools.

Monitor is a programme that makes use of these classes to provide a quick, graphical look at which channels in which modules have been hit, as well as some information on the timing and gain-switching.

PPlot is a that can be used to plot pulses. As splot is not fully functional any more, and since most of its analysis can be quickly done using the later-written classes, it is probably not of much interest to anybody. Monitor and PPlot are useful stand-alone programmes. The set of classes outlined above are handy for doing quick, simple analysis, and may be useful as a starting block for more sophisticated studies.

1.1     Files and Directories

All the files reside on pcfcal01 at CERN. They are all off of the main directory /home/fcaltbmon/adam/ in logically named directories.

The files should make easily enough on other computers. They use the standard C++ libraries as well as some others which are listed in the appendix, all open source/freeware and available online (or from pcfcal01).

Each directory has a Makefile which can be consulted to see what the necessary links and libraries are.



2     Splot


2.1     Description

Interaction with splot (Shape Plotter) is done with a tree of menus. Changes to the menu are saved in a file (.splotsettings) so that values are remembered when the programme is restarted.

The programme can plot pulses, either averaging events together, or displaying them one by a time. This can now be done by a new pulse shape programme. These functions are tasks A, B, and D in the Change Task menu.

It can also create histograms showing which channels are being hit. The more recent monitoring programme is better at this task. Histograms are plotted using task C in the Change Task menu.

The channels and run files to plot are specified in the Data Source menu. Option D, Number of Events, specifies how many events are to be averaged over at a time, when grouped together. The channels are specified using a complicated syntax, explained if you type help after selecting option G.

The Display Settings menu is used to specify how the plots look and is self-explanatory. Other menus should also be self-explanatory.

2.2     Practical Information





3     Runfile Class


3.1     Description

The runfile class provides easy access to FCal run file data. It is an extension in C++ of Petr Gorbunov's C libraries for reading run files. The details of the reading and unpacking are managed by the class in the background so that users need know nothing about the actual data structure. It can be used to read information from the run header, to return a channel's ADC values and gain, the TTC delay values, etc. It is also very fast: a 200 MB run file can be read and unpacked in a few seconds.

See the example to get a better understanding of how it is used.

3.2     Public Functions


runfile()


runfile(char *filename)


runfile(char **filenames, int numfiles)


bool runfile::start(char *filename)


bool runfile::start(char **filenames, int numfiles)


void runfile::getheaderparam(char *key, char *str, int valnum, int maxlen)


int runfile::readnext()


int runfile::unpack()


int runfile::adc(int feb, int chan, int gai, int samp, bool ped)


int runfile::gain(int feb, int chan, int gai)


double runfile::intergain(int feb, int chan, int gai)


double runfile::intergain(int gai)


int runfile::numgains()


int runfile::numsamples()


int runfile::type()


int runfile::runtype()


int runfile::dac()


int runfile::caldelay()


int runfile::dirttc()


int runfile::delttc()


bool runfile::chanpulsed(int chan)


int runfile::eventnum()


double runfile::delay()


bool runfile::triggerbit(int bit)


bool runfile::flagbit(int flag)


bool *runfile::currfilename()


bool runfile::~runfile()


3.3     Defined Constants


3.4     Practical Information


3.4     Example

/*******************************************************************************
 *------------------------------------------------------------------------------
 * rundata_example.cpp
 *------------------------------------------------------------------------------
 * 
 * A basic example showing how to use the runfile class.  In this example, the
 * ADC values of one channel are printed out for every 2500th event.
 *
 * A make file is included in this directory.
 *
 * Adam Hincks
 * 26 August 2003
 *****************************************************************************/

#include <runfile.h>

#define STRING_LEN  16

int main(int argc, char *argv[]) {
  runfile *rf;

  /* We will look at three files. */
  char *files[64] = {"/raid/data/phys/2100-2199/run2119.dat",
                     "/raid/data/phys/2100-2199/run2121.dat",
                     "/raid/data/phys/2100-2199/run2125.dat"};
  const int numfiles = 3;

  int i;
  char momentum1[STRING_LEN], momentum2[STRING_LEN], particle[STRING_LEN];

  /* Initialise the runfile object. */
  rf = new runfile(files, numfiles);

  /* Print out some information from the run header. */
  rf->getheaderparam("BeamMomentum", momentum1, 0, STRING_LEN);
  rf->getheaderparam("BeamMomentum", momentum2, 1, STRING_LEN);
  rf->getheaderparam("BeamParticle", particle, 1, STRING_LEN);
  printf("\n");
  printf("This run was taken with %s %s %s.\n", momentum1, momentum2,
         particle);
  printf("Press enter to continue . . .\n");
  getchar();

  /* Loop until all the files have been read. */
  while (rf->readnext() >= 0) {

    /* Let's only look at every 2500 events, and only if it's a 
     * physics event. */
    if (rf->type() == EVENT_PHYS && rf->eventnum() % 2500 == 0) {
      rf->unpack();  /* Unpack the event. */

      /* Print out the ADC data for FEB 7, channel 89.  We will use a gain index
       * of 0 since these are auto-gain runs.  Also print out the gain of the
       * channel. */
      printf("\n");
      printf("Event %d has gain %d.\n", rf->eventnum(), rf->gain(7, 89, 0));
      printf("FEB 7, Channel 89 ADC values: \n");

      for (i = 0; i < rf->numsamples(); i++)
        printf("  %d -- %d\n", i, rf->adc(7, 89, 0, i, false));
    }
  }

  /* That's it! */
  return 1;
}




4     Plotting & Graphics Classes


4.1     Overview

The plotdata class and the gnuplot class are designed to work together. The plotdata class is a container for plot information, fed to it in arrays of doubles. The plots can be grouped together, and given titles in this class. The gnuplot class is essentially a wrapper for the gnuplot_i C library, which provides a C interface to gnuplot. The gnuplot class is fed plotdata which it displays in a separate window. The user has the ability to vary the style of the plots somewhat, and can output them to the screen, a postscript file, or a printer.

The g2wrapper class is a wrapper for the g2 C graphic library, and provides functions for drawing graphic primitives in a window.

4.2     Practical Information


4.3     Plotdata Class


4.3.1     Description

This is a simple class. The user feds it arrays of doubles containing the x, y, and error in y variables for a plot, which it stores. Pointers to various elements of the plots can be requested, and plots can be subtracted from one another.

4.3.2     Public Functions


void plotdata::clear()


int plotdata::num()


int plotdata::numgroups()


double *plotdata::x(int n, int m)


double *plotdata::y(int n, int m)


double *plotdata::dy(int n, int m)


int plotdata::npoints(int n)


const char *plotdata::gettitle(int n)


void plotdata::add(double *xin, double *yin, double *dyin, int numin, int groupnum, char *tit)


void plotdata::add(double *xin, double *yin, double *dyin, int numin, int groupnum, char *tit, int febin, int gainin, int dacin, int chanin)


void plotdata::add(double *xin, double *yin, double *dyin, double stretch, int shift, int numin, int groupnum, char *tit)


bool plotdata::loadfile(char *filename)


bool plotdata::hasdata()


void plotdata::subtract(double y, double dy)


void plotdata::subtract(double *y, double *dy, int n)


void plotdata::getchaninfo(int n, int *febout, int *gainout, int *dacout, int *chanout)


4.4     Gnuplot Class


4.4.1     Description

A plotdata object can be visualised in gnuplot using this class, while the programme is running. It makes use of the C library gnuplot_i and makes it a bit quicker to use, sacrificing flexibility for ease of use.

4.4.2     Public Functions


gnuplot::gnuplot()


void gnuplot::draw(plotdata *plot, double *topy, double *topx, double *boty, double *botx)


void gnuplot::draw(plotdata *plot)


gnuplot::close()


void gnuplot::setstyle(bool xn, bool yn, char *xl, char *yl, char ti, char ou, char ori, bool er, char *pr, bool ma, char li, int lw)


void gnuplot::setpoints(char poi)


void gnuplot::setcolours(bool cols)


void gnuplot::setoutput(char ou)


bool setxrange(char *parsestr)


bool setyrange(char *parsestr)


4.4.3     Defined Constants


4.5     Plotting + Gnuplot Example

/*******************************************************************************   
 *------------------------------------------------------------------------------
 * rundata_example.cpp
 *------------------------------------------------------------------------------
 * 
 * The pulses from 4 channels are plotted event by event.  This example shows
 * how a short programme can be written to rapidly visualise events -- without
 * comments there are less than 50 lines of code.
 *
 * A make file is included in this directory.
 *
 * Adam Hincks
 * 26 August 2003
 *****************************************************************************/

#include <runfile.h>
#include <plotting.h>

int main(int argc, char *argv[]) {
  int i, j;
  double **x, **y, **dy;
  char temptitle[80];
  runfile *rf;
  plotdata *p = new plotdata();  /* These objects can always be constructed */
  gnuplot *gp = new gnuplot();   /* right away. */

  /* We'll plot some pulse shapes from a run file. */
  rf = new runfile("/raid/data/phys/1500-1599/run1555.dat");

  /* Allocate the arrays for the data points.  We'll make four plots.*/
  x = new double*[4];
  y = new double*[4];
  dy = new double*[4];
  for (i = 0; i < 4; i++) {
    x[i]  = new double[rf->numsamples()];
    y[i]  = new double[rf->numsamples()];
    dy[i] = new double[rf->numsamples()];
  }

  while (rf->readnext() >= 1) {

    /* Unpack only physics events. */
    if (rf->type() == EVENT_PHYS) {
      rf->unpack();

      /* Fill up our arrays with the data points.  We'll look at FEB 6, channels
       * 22-25, using gain index 0 since this is an auto-gain run. */
      for (i = 0; i < rf->numsamples(); i++) {
        for (j = 0; j < 4; j++) {
          x[j][i] = i * PERIOD;
          y[j][i] = rf->adc(6, 22 + j, 0, i, false);
          dy[j][i] = i * 10 + j;  /* Assign a phony error in this example. */
        }
      }

      /* Clear the plotdata object of any previous plots. */
      p->clear();

      /* Fill the plotdata objects with our four plots. */
      for (i = 0; i < 4; i++) {
        sprintf(temptitle, "FEB 6, Channel %d, Event %d", 22 + i,
                rf->eventnum());

        /* Let's group the plots in two.  By using (int)(i / 2) for the group 
         * number, we place plots i = 0, 1 in one set of axes, and i = 2, 3 in 
         * another. */
        p->add(x[i], y[i], dy[i], rf->numsamples(), (int)(i / 2), temptitle);
      }

      /* Now set the styles for gnuplot. See the documentation for details on
       * this function. */
      gp->setstyle(true, true, "Time (ns)", "Raw ADC", GP_TITINSIDE, GP_SCREEN,
                   GP_ROWS, true, "40-1D-COR", true, GP_HISTOGRAM, 1);

      /* Set the range of the y-axis to something reasonable. */
      gp->setyrange("500:2000");

      /* Only look at the first few samples. */
      gp->setxrange("0:250");

      /* Distinguish overlayed plots with different colours. */
      gp->setcolours(true);

      /* Draw the graph. */
      gp->draw(p);

      /* Wait for user input before moving to next event. */
      printf("Press enter to move to the next event, or ctrl-c to exit. ");
      fflush(stdout);
      getchar();
    }
  }
  
  return 1;
}

4.6     G2Wrapper Class


4.6.1     Description

This class is a very simple C++ wrapper for the g2 C library. It is used to draw graphic primitives to a window. I have added a more easy-to-use colour management system. Another substantial addition by me is a function (drawtgif) which reads in a tgif image and draws it to the window. This is useful in conjunction with tgif output from the gnuplot class (see GP_TGIF) -- this is how the inset plots in the monitor programme are created.

4.6.2     Public Functions


g2wrapper::g2wrapper(int xsize, int ysize, int xpos, int ypos, char *title, char *icon, char *icondata, int icon_width, int icon_height)


g2wrapper::g2wrapper(int xsize, int ysize, int xpos, int ypos, char *title, char *icon, char *icondata, int icon_width, int icon_height, char dest)


g2wrapper::g2wrapper()


void g2wrapper::openwind(int xsize, int ysize, int xpos, int ypos, char *title, char *icon, char *icondata, int icon_width, int icon_height)


void openpsfile(enum g2_PS_paper pare, enum g2_PS_orientation ori)


bool g2wrapper::createcolour(char *name, double re, double gr, double bl)


bool g2wrapper::drawtgif(char *filename, double xpos, double ypos, double xstretch, double ystretch)


void g2wrapper::rectangle(double x1, double y1, double x2, double y2, char *colour, bool filled)


void g2wrapper::ellipse(double x, double y, double rx, double ry, char *colour, bool filled)


void g2wrapper::polygon(int numvectors, double *coords, char *colour, bool filled)


void g2wrapper::void line(double x1, double y1, double x2, double y2, char *colour)


void g2wrapper::void text(char *txt, double x, double y, double size, char *colour)


g2wrapper::~g2wrapper


4.6.3     Defined Constants


4.6.4     Example

/*******************************************************************************
 *------------------------------------------------------------------------------
 * g2wrapper_example.cpp
 *------------------------------------------------------------------------------
 *
 * Demo for the features in the g2wrapper class.
 *
 * A make file is included in this directory.
 *
 * A sample tgif file (sample.tgif) is included in this directory.
 *
 * Adam Hincks
 * 28 August 2003
 ******************************************************************************/

#include <plotting.h>
#include <utils.h>

int main(int argc, char *argv[]) {
  char tmpcolour[G2_COLOURLEN];
  double poly[] = {100, 350, 110, 300, 200, 290, 210, 390, 150, 350};
  const int polynum = 5;
  int i, j;
  g2wrapper *g;

  g = new g2wrapper(400, 400, 0, 0, "Demo: g2wrapper", "", "", 0, 0);

  /* These colours are specified in the tgif file.  If we don't declare them, it
   * will draw in black any unrecognised colour names. */
  g->createcolour("black", 0, 0, 0);
  g->createcolour("red", 1, 0, 0);
  g->createcolour("green", 0, 1, 0);
  g->createcolour("blue", 0, 0, 1);
  g->createcolour("magenta", 1, 0, 1);
  g->createcolour("cyan", 0, 1, 1);
  g->createcolour("yellow", 1, 1, 0);
  g->createcolour("DarkSeaGreen", 0, 0.5, 1);
  g->createcolour("HotPink", 1, 0.5, 0);
  g->createcolour("coral", 0.5, 1, 0);

  /* Let's make a gradation of blue colours. */
  for (i = 10; i > 0; i--) {
    sprintf(tmpcolour, "blue%d", i);
    g->createcolour(tmpcolour, 0, 0, (double)(i / 10.0));
  }

  /* Draw some simple shapes. */
  g->ellipse(350, 200, 30, 120, "yellow", true);
  g->line(0, 0, 200, 350, "cyan");
  g->rectangle(20, 25, 200, 50, "red", false);
  g->polygon(polynum, poly, "magenta", true);

  /* Play with our blue gradation. */
  for (i = 10; i > 0; i--) {
    sprintf(tmpcolour, "blue%d", i);
    for (j = 0; j < 3; j++)
      g->line(230, i * 3 + j, 399, i * 3 + j, tmpcolour);
  }

  /* Draw a tgif image. */
  if (!g->drawtgif("./sample.tgif", 50, 50, 0.4, 0.4))
    printf("Someone must have removed the \"sample.tgif\" file from this "
           "directory.\n");

  /* Wait for user input to end.  Graphics windows close automatically when 
   * programme terminates. */
  printf("Press enter to end.\n");
  getchar();

  return 1;
}





5     Process Class


5.1     Overview

The idea of this class is to automate the most generic, basic analyses and processing of runfiles. The class can currently perform three tasks:

Active channels (channels that receive substantial energies) are also identified, but currently the user has no direct access to these data through this class. A class in the utils library can be used instead.

The class is designed in a way that it should be relatively easy to add new tasks, as should be apparent from looking at the header file.

Run files are only analysed once for pedestals, TTC timing information and active channels. The first time they are accessed they are analysed and the information is written to a file. The files are stored in a directory structure, described below, and read each subsequent time the run file is accessed. This makes processing of the data faster.

The algorithms for finding pedestals and determining timing are described below.

The class does not read in the run files independantly. It requires a runfile object to work -- see the example to see how it works.

5.2     Directory Structure and File Formats

Active channel information, pedestals, timing data, and intergain values are all stored in separate directories off of a main directory. On pcfcal01, this is /home/fcaltbmon/adam/rundata. The directories are specified using defined values beginning with PROC_DIR_ — see process.h.

All files are ASCII text files. The first line gives the version number of the algorithm used to generate it; it will be replaced if out of date next time its associated run file is accessed.

Pedestals

Files are given the run file name appended by "peds", e.g., run1555.dat has pedestal file run1555.dat.peds. The file format is:


Active channels

Files are given the run file name appended by "chans", e.g., run1555.dat has active channels file run1555.dat.chans. The first three lines specify, in order:

Subsequent entries follow the format:

Intergain

There is one file, intergain.dat. The three lines are the factors the ADC values must be multiplied to account for the gains, in the order low, medium and high. The high-gain data are considered already normalised; the multiplicative value is 1. The medium-gain value (9.4) was determined using calibration files. The low-gain value was not properly determined and in this file is merely 9.42.

Timing

There is one file of constants, constants.dat. It contains four values, in order,

There are also files, associated with run files. They are named by appending the run file name by "chans", e.g., run1555.dat has timing file run1555.dat.tim. values listed are, in order (see algorithms below for terminology) :


5.3     Algorithms

5.3.1     Pedestals

Pedestals are calculated for each channel at each gain – 1024 x 3 in total. To to so, the run file is read through at least three times, once for each gain.

For a given gain, the file is searched for pedestal events. (In-spill and out-of-spill events are not distinguished.) If pedestal events for the given gain exist, the pedestal is calculated by averaging together all the samples from these events. If they do not exist, the file is read again, and this time the first sample from physics and/or calibration events are used instead to find the pedestals. In both cases the RMS of each pedestal is calculated; this is the channel's noise.

This process is repeated three times, once for each gain.

Pedestals vary significantly between channel to channel and gain to gain. However, by comparing the pedestal for one channel at a specified gain calculated from run files spread over time, I found that it does not vary significantly. For this reason, it is sufficient to use the pedestals calculated from a single run file, usually a pedestal file, for any run. This can be done by specifying a "master pedestal file", either in the constructor or by calling usemasterpedfile. Calculating pedestals for each run file is still useful to monitor the noises, which can be looked at in the output files.

5.3.2     Timing

I have written a separate paper on how the timing is calculated, Reconstructing the Trigger Delay from the TTC Values for FCal Physics Data.

5.3.3     Hit Channels

See the description of the hitchans class.

5.4     Public Functions


process::process()


process::process(bool pedson, bool igainson, bool timeingon)


process::process(bool pedson, char *masterpedfile, bool igainson, bool timeingon)


void process::pedson()


void process::pedsoff()


void process::usemasterpedfile(char *filename)


void process::useeachpedfile()


void process::intergainon()


void process::intergainoff()


void process::timingon()


void process::timingoff()


void process::init(runfile *runf)


double process::adc(int feb, int chan, int gai, int samplenum)


double process::delaytime()


5.5     Practical Information


5.6     Example

/*******************************************************************************
 *------------------------------------------------------------------------------
 * process_example.cpp
 *------------------------------------------------------------------------------
 *
 * In this example, ten run files are read, and scanned for events where the
 * maximum sample of FEB 6, Chan 23 is at least 1500 ADC counts.  The pulses
 * from all the events are overlayed on one another to create a coarse pulse
 * shape.
 *
 * A make file is included.
 *
 * Adam Hincks
 * 29 August 2003
 ******************************************************************************/

#include <runfile.h>
#include <process.h>
#include <plotting.h>

int main(int argc, char *argv[]) {
  int i;
  double delay;
  double x[100000], y[100000];
  double *samples;
  int numpoints = 0;
  char **files;
  const int numfiles = 10;
  runfile *rf;
  process *pr;
  plotdata *p = new plotdata();
  gnuplot *gp = new gnuplot();

  /* We will read in a sequence of ten run files, run1555.dat - run1564.dat.
   * These are 32 sample physics runs. */
  files = new char*[numfiles];
  for (i = 0; i < numfiles; i++) {
    files[i] = new char[64];
    sprintf(files[i], "/raid/data/phys/1500-1599/run%d.dat", 1555 + i);
  }

  rf = new runfile(files, numfiles);

  /* We enable pedestal subtraction, gain multiplication, and timing
   * information.  We specify a master pedestal file in the second argument. */
  pr = new process(true, "/raid/data/pedestal/ped3400.dat", true, true);

  samples = new double[rf->numsamples()];

  /* Always remember to initialise the process object by telling it which run
   * file is being used. */
  pr->init(rf);

  /* Read through the run files. */
  while (rf->readnext() >= 0) {

    /* If rf->type() returns 0, it means that a file has just been finished and
     * the next one in the list opened.  We need to initialise the process
     * object again so that it knows a new file has been opened. */
    if (!rf->type())
      pr->init(rf);

    else if (rf->type() == EVENT_PHYS) {
      rf->unpack();

      /* If we can't get a delay, discard the event. */
      if ((delay = pr->delaytime()) == NO_TIMING)
        continue;

      /* Get the pulse information for this event.  We look at FEB 6, channel
       * 23, using a gain index of 0 since these are auto-gain runs. */
      for (i = 0; i < rf->numsamples(); i++)
        samples[i] = pr->adc(6, 23, 0, i);

      /* Only consider events with a sizeable amplitude so that the pulse shape
       * looks cleaner. */
      if (samples[maxvalueindex(samples, i)] < 1500)
        continue;

      /* Record the points for this event. */
      for (i = 0; i < rf->numsamples(); i++) {
        /* Add the delay to the time axis. */
        x[numpoints] = i * PERIOD + delay;

        /* Use the process::adc function.  It automatically subtracts the
         * pedestals and mulitplies by the correct gain. */
        y[numpoints++] = pr->adc(6, 23, 0, i);
      }
    }
  }

  /* Plot x and y. */
  p->add(x, y, NULL, numpoints, 0, "");
  gp->setstyle(true, true, "Time (ns)", "Amplitude (ADC)", GP_TITABOVE,
               GP_SCREEN, GP_ROWS, false, "40-1D-COR", true, GP_DOTS, 1);
  gp->draw(p);

  printf("Press enter to end.\n");
  getchar();

  return 1;
}




6     Utility Classes and Functions


6.1     Miscellaneous Functions and Structures


struct channel


bool isnumber(char *str, bool neg, bool dec)


void sort(double *left, double *right)


void associatedsort(double *left, double *right, double **aleft, double **aright, int anum)


int maxvalueindex(double *list, int num)


void fitparabola(double *x, double *y, double *a, double *b, double *c)


double parabolaheight(double a, double b, double c)


double parabolacentre(double a, double b, double c)


bool lininterpolate(double x, double *y, double *dy, double *fx, double *fy, double *fdy, int num)


int truncate(double value)


6.2     Histogram Class


6.2.1     Description

This class fills a histogram, without the user needing to specify upper or lower limits before hand. All it requires is a bin size, and then the user keeps sending it values using the add function. The values are automatically binned. The histogram can be returned to the user using the get function, which writes array of doubles to provided pointers.

The histogram storage is not optimal in terms of memory efficiency, but should cause no problems for reasonable data.

6.2.2     Public Functions


histogram::histogram()


histogram::histogram(double binsize)


void histogram::setbinsize(double binsize)


void histogram::clear()


double histogram::add(double value)


double histogram::add(double value, double weight)


double histogram::max()


double histogram::min()


int histogram::numbins()


double histogram::binsize()


void histogram::get(double **x, double **y, int *size)


void histogram::get(double **x, double **y, int *size, double min, double max)


6.3     Hitchans Class


6.3.1     Description

This class examines a run file to see which channels are receiving significant energies. It creates a list of these channels with some basic statistics on the channels' activities. The user specifies a number of events in the constructor or with setnumevents. The file is read until this number of events has been looked at. For these events, any channels whose maximum samples exceed a threshold energy (specified in the constructor or with setminamplitude are recorded. A running total of each of these channel's energy and the number of times it was hit is also recorded.

6.3.2     Public Functions


hitchans::hitchans()


hitchans::hitchans(double minamplitude, int numevents)


hitchans::hitchans(char *filename, double minamplitude, int numevents)


void hitchans::setminamplitude(double minamp)


void hitchans::setnumevents(int numevents)


hitchans::hitchans(char *filename, double minamplitude, int numevents)


channel hitchans::list(int index)


int hitchans::numhit()


channel hitchans::maxenergychan()


int hitchans::maxenergyindex()


double hitchans::totalenergy(int index)


double hitchans::avgenergy(int index)


int hitchans::numtimeshit(int index)


6.4     Practical Information


6.5     Example

/*******************************************************************************
 *------------------------------------------------------------------------------
 * utils_example.cpp
 *------------------------------------------------------------------------------
 *
 * This example shows the hitchans and histogram class from the utils library,
 * as well as some of its other functions.
 *
 * The hitchans class is used to identify the channels in one of the FEBS which
 * have been hit with particles.  A histogram is drawn showing the relative
 * energies received by the hit channels.
 *
 * The run file is then read through and the amplitude of the hottest channel is
 * studied.  Another histogram is plotted showing the energy distribution for
 * this channel.
 *
 * This example makes use of the runclass, plotdata, gnuplot and process
 * classes.  Example files for them are in this directory.
 *
 * A make file is included.
 *
 * Adam Hincks
 * 29 August 2003
 ******************************************************************************/

#include <runfile.h>
#include <process.h>
#include <plotting.h>
#include <utils.h>

int main(int argc, char *argv[]) {
  int i, j;
  char runfilename[] = {"/raid/data/phys/1500-1599/run1555.dat"};
  char tmpstr[80];
  double *histox, *histoy;
  double *samples, *times;
  double a, b, c;
  int histosize;
  channel hotchan;
  runfile *rf;
  process *pr;
  histogram *h;
  hitchans *hc;
  plotdata *p = new plotdata();
  gnuplot *gp = new gnuplot();

  /* Initialise the object, and search runfilename for the hit channels. */
  hc = new hitchans(runfilename, 50, 250);

  /* Prepare a histogram with a bin width of 1. */
  h = new histogram(1);

  /* Look through the hit channels in FEB 6.  Fill a histogram with their total
   * energies over the 250 events. */
  for (i = 0; i < hc->numhit(); i++) {
    if (hc->list(i).feb == 6)
      h->add(hc->list(i).chan, hc->totalenergy(i));
  }

  /* Extract the histogram into the arrays histox[] and histoy[], filling them
   * from 0 to 127. */
  h->get(&histox, &histoy, &histosize, 0, 127);

  /* Plot. */
  p->add(histox, histoy, NULL, histosize, 0,
         "Total Energy Received by Channels for FEB 6 (250 events)");
  gp->setstyle(true, true, "Channel", "Total Energy (ADC)", GP_TITABOVE,
               GP_SCREEN, GP_ROWS, false, "40-1D-COR", true, GP_HISTOGRAM, 1);
  gp->setxrange("-1:128");
  gp->draw(p);

  printf("\nPress enter to continue. ");
  fflush(stdout);
  getchar();

  /* Now let's look at the most active channel. */
  hotchan = hc->maxenergychan();

  /* This time we'll plot the ADC distribution for the hot channel.  Clear the
   * histogram and set the bin width to 50 ADC. */
  h->clear();
  h->setbinsize(50);

  /* Prepare the runfile and process classes. */
  pr = new process(true, true, true);
  rf = new runfile(runfilename);
  samples = new double[rf->numsamples()];
  times = new double[rf->numsamples()];
  pr->init(rf);

  while (rf->readnext() >= 0) {

    /* Look only at physics events. */
    if (rf->type() == EVENT_PHYS) {
      rf->unpack();

      /* Get the samples and timing for this event for the hot channel. */
      for (i = 0; i < rf->numsamples(); i++) {
        samples[i] = pr->adc(hotchan.feb, hotchan.chan, hotchan.gain, i);
        times[i] = i * PERIOD + pr->delaytime();
      }

      /* Require that the maximum sample for this event be at least 50 ADC
       * counts, so that we safely eliminate non-hit events. */
      j = maxvalueindex(samples, rf->numsamples());
      if (samples[j] < 50)
        continue;

      /* Draw a parabola through the top three samples.  The top sample is
       * sample[j], so the top three points are (times[j - 1], samples[j - 1]), 
       * (times[j], sample[j]) and (times[j + 1], sample[j + 1]). */
      fitparabola(times + j - 1, samples + j - 1, &a, &b, &c);

      /* Add the amplitude determined from the peak of the parabola to the
       * histogram. */
      h->add(parabolaheight(a, b, c));
    }
  }

  /* We must deallocate these pointers if we want to use them again. */
  delete histox;
  delete histoy;
  h->get(&histox, &histoy, &histosize);

  /* Clear p and plot the new histogram. */
  p->clear();
  p->add(histox, histoy, NULL, histosize, 0,
         "Energy Distribution of Hottest Channel on FEB 6");
  sprintf(tmpstr, "%f:%f", histox[0], histox[histosize - 1]);
  gp->setxrange(tmpstr);
  gp->setstyle(true, true, "Amplitude (ADC)", "Frequency", GP_TITABOVE,
               GP_SCREEN, GP_ROWS, false, "40-1D-COR", true, GP_HISTOGRAM, 1);
  gp->draw(p);

  printf("\nPress enter to end. ");
  fflush(stdout);
  getchar();

  return 1;
}




7     Monitoring Programme


7.1     Running the Monitor

The run file to read and the display options are specified on the command line, with the syntax: ./monitor [-v] [-gX] [-p] <filename>

The three optional flags are:

Some examples:


7.2     What is Displayed

Two windows are opened when the programme is finished. One contains plots of the ADC spectra of the medium and high gains. By "ADC spectrum" it is meant a histogram of the frequency that channels reach the plotted ADC values. The energies shown on these plots are for individual channels, and have not been summed at all. Only channels which are highlighted in the second window contribute to these plots. These plots are meant to give an indication of how well the gain switching is working.

The second window draws the three modules face on and highlights the channels that have been hit. A beam centre is shown as a green target, and is the average position of the hit channels, weighted by their relative energies.

The numbers in the legend at the top right of the screen are not very meaningful and should only be used to give an indication of relative energies between the channels. (They represent a channel's accumulated energy over events from the beginning of the run file.)

Each module has a small plot labelled "Timing". The x-axis is the sample number, and the histogram records the frequency that a sample is the maximum for an event. Pulses are supposed to peak at the fourth sample, so for well-timed runs, there should be a big peak at the fourth sample.

The "Num. Hits" item in the three menus is the number of events that saw at least one channel being hit. The "Avg. Peak Centre" item begins labeling samples at 0, so an average peak centre of 3 means the fourth sample.

7.3     Changing Settings

The file params.dat in the monitor directory can be modified to change the monitor's settings. (A back-up of this file, default.params.dat is in the directory also in case you make changes you don't know how to undo.) The options are:





8     Pulse Plotting Programme


8.1     Overview

PPlot is a programme for drawing pulses. It is probably buggy because it was the most recent thing I created, and in a hurry. But it is useful for quickly looking at pulses.

PPlot requires a configuration file to run, which specifies the run files and channels to look at, as well as settings for the output plots. There is a programme called pfile, described below, which allows configuration files to be interactively created.

8.2     Creating Configuration Files

PFile is used to interactively create configuration files. It is run simply by entering ./pfile at the command prompt. All configuration files are placed in the directory pconfig. Once created, they can be edited from here and should be simple to decode as they are ASCII text-files. Beware, as pplot does not check thoroughly for valid input, so if, for example, a file is missing a line, it will do strange things.

Below is example input into pfile, with comments preceded by "//".

+--------------------------------------------------------------------------+
|                             WELCOME TO PFILE                             |
|                                                                          |
| PFile is used to create configuration files for pplot.  Here, you        |
| specify runs and channels for pplot to plot pulses from.  You also edit  |
| the styles and output that pplot uses.                                   |
|                                                                          |
+--------------------------------------------------------------------------+

Enter a file name for this configuration: test    // No path should be entered

Enter the run file(s) (with full path) you want to use.  To enter multiple 
files, put each file name on a new line, ending each line with a comma 
(',').  The first line not terminated by a comma is the last file in the 
list.
  -> /raid/data/phys/1500-1599/run1555.dat,      // A final comma means
  -> /raid/data/phys/1500-1599/run1556.dat,      // that there is another file
  -> /raid/data/phys/1500-1599/run1557.dat       // coming

// The run header of the first file is read and some information given to you
Reading /raid/data/phys/1500-1599/run1555.dat . . .

Physics run:
* 200 GeV/c e- at spot unknown (-1)
* 32 samples, gain 0 (autogain)

Enter the channel(s) in the format "FEB Chan Gain" (gain 0 = autogain).  
Multiple channels can be entered the same was as run files.
  -> 6 23 1
Gain 1 is not recorded in this run file.    // Smart input.
  -> g 
Gain 1 is not recorded in this run file.
  -> 6 23 0,     // Again, a list entered using commas
  -> 6 24 0

Look only at physics events for physics runs (y/n)? [Y] y
Use pedestals calculated from the run itself (y/n)? [N] n
Starting event number: [1] 299
Number of events to average together (enter 0 to use all events): [1] 10
Orient plots in <R>ows or <C>olumns? [R]  // Entering nothing keeps the default
Put titles <I>nside or on <T>op of plots? [T] 
Plot with <L>ines, <D>ots or <H>istograms? [L] 
Enter a bin size for histogramming (ns): [25.00] 
Discard events with ambiguous timing (y/n)? [Y] n
Show error bars on plots (y/n)? [Y] n

File successfully saved.  To view plots with it, run ./pplot test


Resulting configuration file:

NumFiles 3
/raid/data/phys/1500-1599/run1555.dat
/raid/data/phys/1500-1599/run1556.dat
/raid/data/phys/1500-1599/run1557.dat
NumChannels 2
6 23 0
6 24 0
Dac -1
OnlyPhysEvents 1
FirstEvent 299
NumEvents 10
Orientation R
TitPosition T
PlotStyle L
HistoSize 25.000000
MasterPed 1
DiscardBadTiming 1
ShowErrBars 1

8.3     Running PPlot

The command line syntax is ./pplot <configfilename>. The pulse is plotted, starting at the first event (FirstEvent in the configuration file), with a number of adjacent events averaged together (NumEvents). Error-bars represent the RMS of this average.

The plot is actually a weighted histogram. That is, each sample of each event is added to a bin depending on its delay. After the NumEvents events have elapsed, each bin is divided by the number of samples added to it, to get the average amplitude for that bin. The default bin-size is 25 ns in pfile, which ends up plotting the samples without any delay worked in. But if, for example, you want to see a more detailed pulse shape, a bin size of, say, 1 ns can be specified, with a large NumEvents. The smallest possible bin size is 0.05 ns, which is the resolution of the timing.

After a plot has been displayed, it can be zoomed, printed or written to a postscript. The next NumEvents events can then be displayed.



9     Other Programmes

There are several small programmes I wrote to do on-the-spot analysis. They provided me with lots of interesting information, but they are quite messy, with little commenting, and were not written with the intention of being versitile tools. I outline them briefly. They are collected in a directory called other.

Adcgain

Noise

Pulse

Quickstudies





Appendix: Software Credits


Petr Gorbunov's Libraries

My runfile class, as well as splot, make use of C libraries written by Petr Gorbunov for reading and unpacking run files.

Originals of these can be found (at the time of writing) on pcfcal01 in /home/daq/Daq/src.

Gnuplot

This is the freeware plotting programme used to create plots with my programmes. It is quite basic, but easy to use. I was using version 3.7; I don't know if earlier versions will work. Its website is http://www.gnuplot.info, with a good manual at http://www.ucc.ie/gnuplot/gnuplot.html.

Gnuplot_i Library

This is a C library which calls gnuplot directly during run time. It was written by N. Devillard and is freely available at http://ndevilla.free.fr/gnuplot/. It is used by my gnuplot class.

N.B.: I added one function to this library called gnuplot_adamxy. The gnuplot class requires this function.

G2 Library

An GPL C library which can be used to create 2D graphics primitives. It is used by my g2wrapper class. It is well documented and can be downloaded from http://g2.sourceforge.net/. I used version 0.49a.

PsJoin

My gnuplot class uses this perl script by Tom Sato to concatinate multiple plots into one file. This is necessary because gnuplot outputs files individually. The script was found at http://member.nifty.ne.jp/tsato/tools/psjoin.html.

Quicksort algorithm

My sort and associatedsort functions use the well-known quicksort algorithm. I modified slightly a version written by Matt Whitlock, available at http://www.whitsoftdev.com/qsort/.