Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Analysis code examples (comparisons of frameworks)

Here's one comparison of an example analysis in three different frameworks:

  • myana (online C++ framework), using ROOT histogramming package
  • psana (offline C++ framework), using ROOT histogramming package
  • pyana (offline python framework)
    • using ROOT histogramming package
    • alternative without ROOT, using NumPy to store arrays and MatPlotLib to plot those arrays/

They all make histograms/plots of AMO ITof wavefunctions, in 20 energy bins (energy measured by FEE Gas Detector).
Timing and plots from all frameworks (pdf)

Composition Setup
cloak.memory.duration = 0
cloak.toggle.type = default
Deck of Cards
idCode Snippets

Card
labelmyana with ROOT

Code Block
titlemyana_esort.cc
// header files for this class
#include "myana.hh"
#include "main.hh"

// these are needed to make ROOT histograms
#include <TROOT.h>
#include <TH1F.h>
#include <TProfile.h>

// for tracking execution time
#include <time.h>

// global variables:
static int                  numChannelsITof;
static int                  numSamplesITof;
static double               sampleIntervalITof;

static const int            maxITofBin = 50;
static TProfile*            profWf[maxITofBin];
static TProfile*            profWfAll;
static TH1F*                histEnrg;
static TH1I*                histBin;

static unsigned int         shotCountITof = 0;

float  e1,e2;
int nenergy;
static int bin;

clock_t start_time;
clock_t finish_time;

using namespace Pds;

// This method is called once per job 
void beginjob() {

  // get ITof parameters from myana.inp (configuration file)
  const char inpname[20]="myana.inp";
  FILE *inpfile;
  inpfile=fopen(inpname,"r");
  fscanf(inpfile,"%d\n",&nenergy); // nbins of histogram
  fscanf(inpfile,"%f\n",&e1); // xmin of histogram
  fscanf(inpfile,"%f\n",&e2); // xmax of histogram
  printf("%d %e %e\n",nenergy,e1,e2);
  fclose(inpfile);

  printf("calling beginjob()\n"); fflush(stdout);

  int i;
  int fail = 0;


  /*
   * Get ITof Config Data at the beginning of the job 
   */
  fail = getAcqConfig( AmoITof, numChannelsITof, numSamplesITof, sampleIntervalITof);

  // create an "averaging" histogram (called "profile")
  profWfAll = new TProfile("profWfAll","Average Waveform;Seconds;Volts"
                           , numSamplesITof
                           , 0.0,sampleIntervalITof,"");
  char name[32];
  char title[232];
  for (i=0;i<nenergy;i=i+1) {
    sprintf(name,"profWf%d",i);
    sprintf(title,"Average Waveform in Energy bin %d",i);
    profWf[i] = new TProfile(name,title,numSamplesITof,
                             0.0,sampleIntervalITof,"");
    profWf[i]->SetYTitle("Volts");    //optional
    profWf[i]->SetXTitle("Seconds");  //optional
  }

  // create a histogram to display the energy bins
  histEnrg = new TH1F("histEnrg","Energy bins;Energy; Event Count",nenergy,e1,e2);
  histBin = new TH1I("histBin","Energy bins;Bin; Event Count",nenergy,0.0,nenergy);
  histEnrg->SetMarkerStyle(4); histEnrg->SetMarkerColor(4); // blue circles
  histBin->SetMarkerStyle(4);  histBin->SetMarkerColor(4); // blue circles

  printf("beginjob is done, starting timer...");
  start_time = clock();

}

// This method is called once per Run 
void beginrun()
{
}

// This method is called once per CalibCycle
void begincalib()
{
}

// This is called once every shot.  You can ask for
// the individual detector shot data here.

void event()
{
  int fail;
  /*
   * Processing FeeGasDet Value for this event
   */
  double shotEnergy[4];
  fail = getFeeGasDet( shotEnergy );
  double energy = (shotEnergy[2]+shotEnergy[3])/2;

  if      ( energy < e1 )    histEnrg->Fill(e1);
  else if ( energy > e2 )    histEnrg->Fill(e2);
  else                       histEnrg->Fill(energy);


  /*
   * Processing ITof waveform for this event
   */
  double* timeITof;
  double* voltageITof;
  int channel = 0;
  fail = getAcqValue( AmoITof, channel, timeITof, voltageITof);
  if ( fail != 0 )
    printf( "event(): getAcqValue() failed, code = %d\n", fail );
  else
  {
    bin = int(( (energy-e1)/(e2-e1) )*nenergy+0.5);
    if (bin<1) bin=0;
    if (bin>nenergy-1) bin=int(nenergy-1);
    for (int i=0;i<numSamplesITof;i=i+1)
      {
        double t = timeITof[i];
        double v = voltageITof[i];
        profWf[bin]->Fill(t,v);

        profWfAll->Fill(t,v);
      }
    histBin->Fill(bin);
    shotCountITof++;
  }

}

void endcalib()
{
}


void endrun()
{
  printf("User analysis endrun() routine called.\n");
}

void endjob()
{
  printf("User analysis endjob() routine called.\n");
  finish_time = clock();
  double duration = (finish_time - start_time)/CLOCKS_PER_SEC;
  printf("Time elapsed: %.2f s \n",(duration));
  printf("Number of events processed: %d \n", shotCountITof);

  printf("%d \n",profWfAll->GetNbinsX());
  for (int bin=20;bin<40;bin++){
    printf("%.10f +- %.10f \n",profWfAll->GetBinContent(bin+1),profWfAll->GetBinError(bin+1));
  }
}
Card

Card
labelpsana with ROOT

Code Block
title"psana_esort.cpp"
//-----------------------
// This Class's Header --
//-----------------------
#include "speed/psana_esort.h"

//-----------------
// C/C++ Headers --
//-----------------
#include <time.h>

//-------------------------------
// Collaborating Class Headers --
//-------------------------------
#include "MsgLogger/MsgLogger.h"

//--------------------------------------------------
// to work with detector data include corresponding
// header from psddl_psana package
//--------------------------------------------------
#include "psddl_psana/acqiris.ddl.h"
#include "psddl_psana/bld.ddl.h"

//-----------------------------------------------------------------------
// Local Macros, Typedefs, Structures, Unions and Forward Declarations --
//-----------------------------------------------------------------------

// This declares this class as psana module
using namespace speed;
PSANA_MODULE_FACTORY(psana_esort)

//              ----------------------------------------
//              -- Public Function Member Definitions --
//              ----------------------------------------

namespace speed {

//----------------
// Constructors --
//----------------
psana_esort::psana_esort (const std::string& name)
  : Module(name)
  , m_acqSrc()
  , m_feeSrc()
  , m_maxEvents()
  , m_filter()
  , m_nenergy()
  , m_e1()
  , m_e2()
{
  // get the values from configuration or use defaults
  m_acqSrc = configStr("acqSource", "DetInfo(:Acqiris)");
  m_feeSrc = configStr("feeSource", "BldInfo(FEEGasDetEnergy)");
  m_maxEvents = config("events", 32U);
  m_filter = config("filter", false);
  m_nenergy = config("nenergy",20);
  m_e1 = config("e1",0.0);
  m_e2 = config("e2",4.0);
}

//--------------
// Destructor --
//--------------
psana_esort::~psana_esort ()
{
}

/// Method which is called once at the beginning of the job
void
psana_esort::beginJob(Env& env)
{
  m_count = 0;

  RootHistoManager::RootHMgr& rhmgr = env.rhmgr();

  shared_ptr<Psana::Acqiris::ConfigV1> acqConfig = env.configStore().get(m_acqSrc);
  if (acqConfig.get()) {
    int channel = 0;
    m_nSamples       = acqConfig->horiz().nbrSamples();
    m_sampleInterval = acqConfig->horiz().sampInterval();
    m_slope          = acqConfig->vert(channel).slope();
    m_offset         = acqConfig->vert(channel).offset();

    m_timevector = new double[m_nSamples];
    m_wfvector = new double[m_nSamples];
    m_wgvector = new double[m_nSamples];
    for (int i(0);i<m_nSamples;i++){
      m_timevector[i]= i * m_sampleInterval;
      m_wfvector[i]=0.0;
      m_wgvector[i]=1.0;
    }

    m_profWfAll = rhmgr.profile("profWfAll","Average Waveform;time [s];voltage [V]",
                                AxisDef(0.0, m_nSamples*m_sampleInterval,m_nSamples)
                                );

    char name[32];
    char title[232];
    for (int i=0; i<m_nenergy;i++){
      sprintf(name,"profWf%d",i);
      sprintf(title,"Average Waveform in Energy bin %d; time [s]; voltage [V]",i);
      m_profWf[i] = rhmgr.profile(name, title,
                                  AxisDef(0.0,m_nSamples*m_sampleInterval,m_nSamples)
                                  );
    }
  }
  // create a histogram to display the energy bins
  m_histEnrg = rhmgr.h1f("histEnrg","Energy bins;Energy; Event Count",AxisDef(m_e1,m_e2,m_nenergy));
  m_histBin = rhmgr.h1i("histBin","Energy bins;Bin; Event count",AxisDef(0.0,m_nenergy,m_nenergy));
  m_histEnrg->SetMarkerStyle(4); m_histEnrg->SetMarkerColor(4); // blue circles
  m_histBin->SetMarkerStyle(4);  m_histBin->SetMarkerColor(4); // blue circles

}


/// Method which is called at the beginning of the run
void
psana_esort::beginRun(Env& env)
{
  printf("beginRun is done, starting timer...");
  m_start_time = clock();
}

/// Method which is called at the beginning of the calibration cycle
void
psana_esort::beginCalibCycle(Env& env)
{
}

/// Method which is called with event data, this is the only required
/// method, all other methods are optional
void
psana_esort::event(Event& evt, Env& env)
{
  //MsgLog(name(),info,"Event:" << m_count);

  /*
   * Processing FeeGasDet Value
   */
  shared_ptr<Psana::Bld::BldDataFEEGasDetEnergy> fee = evt.get(m_feeSrc);
  double shotEnergy[4] = {0.,0.,0.,0.};
  if (fee.get()) {
    shotEnergy[0] = fee->f_11_ENRC();
    shotEnergy[1] = fee->f_12_ENRC();
    shotEnergy[2] = fee->f_21_ENRC();
    shotEnergy[3] = fee->f_22_ENRC();
  }
  double energy = (shotEnergy[2]+shotEnergy[3])/2;
  if ( energy < m_e1 ) {
    m_histEnrg->Fill(m_e1);
  } else if ( energy > m_e2 ) {
    m_histEnrg->Fill(m_e2);
  } else {
    m_histEnrg->Fill(energy);
  }

  /*
   * Processing ITof waveform
   */
  shared_ptr<Psana::Acqiris::DataDescV1> acqData = evt.get(m_acqSrc);
  if (acqData.get()) {

    m_count++;

    int channel = 0;
    const Psana::Acqiris::DataDescV1Elem& data = acqData->data(channel);

    // copy myana main.cc getAcqValue()
    const int16_t* wfdata = data.waveforms();
    wfdata += data.indexFirstPoint();

    shared_ptr<Psana::Acqiris::ConfigV1> acqConfig = env.configStore().get(m_acqSrc);
    if (acqConfig.get()) {

      for (int j=0;j<m_nSamples;j++){
        m_wfvector[j] = wfdata[j] * m_slope - m_offset;
      }


      int numSamples = data.nbrSegments() * data.nbrSamplesInSeg();
      if (numSamples != m_nSamples) std::cout << "nSamples mismatch" << std::endl;

      int bin = int(( (energy-m_e1)/(m_e2-m_e1) )*m_nenergy+0.5);
      if (bin<1) bin=0;
      if (bin>m_nenergy-1) bin=int(m_nenergy-1);


      m_histBin->Fill(bin);
      m_profWf[bin]->FillN(numSamples,m_timevector,m_wfvector,m_wgvector,1);
      m_profWfAll->FillN(numSamples,m_timevector,m_wfvector,m_wgvector,1);
    }
  }
}

/// Method which is called at the end of the calibration cycle
void
psana_esort::endCalibCycle(Env& env)
{
  delete[] m_timevector;
}

/// Method which is called at the end of the run
void
psana_esort::endRun(Env& env)
{
}

/// Method which is called once at the end of the job
void
psana_esort::endJob(Env& env)
{

  clock_t finish_time = clock();
  double duration = (finish_time - m_start_time)/CLOCKS_PER_SEC;
  printf("Time elapsed: %.2f s \n",(duration));
  printf("Number of events processed: %d \n", m_count);

  std::cout << m_profWfAll->GetNbinsX() << std::endl;
  for (int bin = 20; bin<40; bin++) {
    std::cout << m_profWfAll->GetBinContent(bin+1) << " +- " << m_profWfAll->GetBinError(bin+1) << std::endl;
  }
}

} // namespace speed

Card

Card
labelpyana with ROOT

Code Block
title"pyana_esort_hmgr.py"
import sys
import logging
import time

#-----------------------------
# Imports for other modules --
#-----------------------------
import numpy as np
import matplotlib.pyplot as plt

#---------------------
#  Class definition --
#---------------------
class pyana_esort_hmgr (object) :
    """Class whose instance will be used as a user analysis module. """
    #----------------
    #  Constructor --
    #----------------
    def __init__ ( self, nenergy, e1, e2, source = "AmoITof-0|Acqiris-0"):
        """Class constructor. The parameters to the constructor are passed
        from pyana configuration file. If parameters do not have default
        values  here then the must be defined in pyana.cfg. All parameters
        are passed as strings, convert to correct type before use.
        """
        self.source = source
        self.nebins = int(nenergy)
        self.emin = float(e1)
        self.emax = float(e2)

        self.nev = 0

    #-------------------
    #  Public methods --
    #-------------------

    def beginjob( self, evt, env ) :
        """This method is called once at the beginning of the job.
        It will also be called in any Xtc Configure transition, if
        configurations have changed since last it was run.

        @param evt    event data object
        @param env    environment object
        """

        # Preferred way to log information is via logging package
        logging.info( "pyana_esort_hmgr.beginjob() called " )

        cfg = env.getAcqConfig(self.source)
        #numChannels = cfg.nbrChannels()
        self.numSamplesITof = cfg.horiz().nbrSamples()
        sampleIntervalITof = cfg.horiz().sampInterval()
        print self.numSamplesITof
        print sampleIntervalITof

        hmgr = env.hmgr()

        self.histEnrg = hmgr.h1f("histEnrg",";Energy",self.nebins,self.emin,self.emax)
        self.histBin = hmgr.h1i("histBin",";Bin",self.nebins,0.0, self.nebins)
        self.histEnrg.SetMarkerStyle(4)
        self.histEnrg.SetMarkerColor(4)
        self.histBin.SetMarkerStyle(4)
        self.histBin.SetMarkerColor(4)

        name = "profWfAll"
        title = "Average Waveform;time [s];voltage [V]"
        self.prof_wfAll = hmgr.prof(name,title,self.numSamplesITof,
                                    0.0,
                                    self.numSamplesITof*sampleIntervalITof,
                                    "")
        self.prof_wf = []
        for bin in range (0,self.nebins):
            name = "profWf%d"%bin
            title = "Average Waveform in Energy Bin %d;time [s];voltage [V]" % bin
            self.prof_wf.append( hmgr.prof(name,title,self.numSamplesITof,
                                           0.0,
                                           self.numSamplesITof*sampleIntervalITof,
                                           ""))


        # prof.FillN requires a weight array...
        self.wg = np.ones(self.numSamplesITof,dtype=float)
        self.ts = None

    def beginrun( self, evt, env ) :
        """This optional method is called if present at the beginning
        of the new run.

        @param evt    event data object
        @param env    environment object
        """
        logging.info( "pyana_esort_hmgr.beginrun() called ")

        print "beginrun is done, starting timer..."
        self.start = time.clock()

    def begincalibcycle( self, evt, env ) :
        """This optional method is called if present at the beginning
        of the new calibration cycle.

        @param evt    event data object
        @param env    environment object
        """
        logging.info( "pyana_esort_hmgr.begincalibcycle() called ")




    def event( self, evt, env ) :
        """This method is called for every L1Accept transition.

        @param evt    event data object
        @param env    environment object
        """
        logging.info( "pyana_esort_hmgr.event() called ")
        self.nev+=1

        shotEnergy = evt.getFeeGasDet()
        energy = 0.0
        bin = 0
        if shotEnergy is None :
            print "No Gas Detector"
        else :
            energy = (shotEnergy[2]+shotEnergy[3])/2
            self.histEnrg.Fill(energy);

        acqData = evt.getAcqValue(self.source, 0, env)
        if acqData :
            wf = acqData.waveform()

            if self.ts is None :
                self.ts = acqData.timestamps()

            self.prof_wfAll.FillN(self.numSamplesITof,self.ts,wf,self.wg,1)

            bin = int( ((energy-self.emin)/(self.emax-self.emin))*self.nebins+0.5)
            if bin < 1 : bin = 0
            if bin > self.nebins : bin = self.nebins-1
            self.histBin.Fill(bin)
            self.prof_wf[bin].FillN(self.numSamplesITof,self.ts,wf,self.wg,1)


    def endcalibcycle( self, env ) :
        """This optional method is called if present at the end of the
        calibration cycle.

        @param env    environment object
        """

        logging.info( "pyana_esort_hmgr.endcalibcycle() called" )

    def endrun( self, env ) :
        """This optional method is called if present at the end of the run.

        @param env    environment object
        """
        logging.info( "pyana_esort_hmgr.endrun() called" )

    def endjob( self, env ) :
        """This method is called at the end of the job. It should do
        final cleanup, e.g. close all open files.

        @param env    environment object
        """
        logging.info( "pyana_esort_hmgr.endjob() called" )

        duration = time.clock() - self.start
        print "duration in seconds : ", duration
        print "Number of events processed: ", self.nev

        print self.prof_wfAll.GetNbinsX()
        for bin in range (20,40):
            print self.prof_wfAll.GetBinContent(bin+1), " +- ", self.prof_wfAll.GetBinError(bin+1)

Card

Card
labelpyana with MatPlotLib

Code Block
title"pyana_esort_mpl.py"
import sys
import logging
import time

#-----------------------------
# Imports for other modules --
#-----------------------------
import numpy as np
import matplotlib.pyplot as plt
import h5py

#---------------------
#  Class definition --
#---------------------
class pyana_esort_mpl (object) :
    """Class whose instance will be used as a user analysis module. """

    #----------------
    #  Constructor --
    #----------------
    def __init__ ( self, nenergy, e1, e2, source = "AmoITof-0|Acqiris-0"):
        """Class constructor. The parameters to the constructor are passed
        from pyana configuration file. If parameters do not have default
        values  here then the must be defined in pyana.cfg. All parameters
        are passed as strings, convert to correct type before use.
        """
        self.source = source
        self.nebins = int(nenergy)
        self.emin = float(e1)
        self.emax = float(e2)
        self.bwidth = (self.emax-self.emin)/self.nebins

        self.nev = 0

    #-------------------
    #  Public methods --
    #-------------------

    def beginjob( self, evt, env ) :
        """This method is called once at the beginning of the job.
        It will also be called in any Xtc Configure transition, if
        configurations have changed since last it was run.

        @param evt    event data object
        @param env    environment object
        """

        # Preferred way to log information is via logging package
        logging.info( "pyana_esort_mpl.beginjob() called " )

        cfg = env.getAcqConfig(self.source)
        #numChannels = cfg.nbrChannels()
        self.numSamplesITof = cfg.horiz().nbrSamples()
        sampleIntervalITof = cfg.horiz().sampInterval()

        # for matplotlib, we store the array till the end instead of a histogram...
        """ energy / bin histogram """
        self.axisEnrg = np.arange(self.emin,self.emax,self.bwidth, dtype=float)
        self.arrayEnrg = np.zeros(self.nebins, dtype=float)
        """ time wave"""
        self.ts = None

        """ voltage wave"""
        self.wf = None
        self.wf2 = None

        """ voltage wave in bins of energy  """
        self.bwf = []
        self.bwf2 = []
        for bin in range (0, self.nebins):
            self.bwf.append( None )
            self.bwf2.append( None )

    def beginrun( self, evt, env ) :
        """This optional method is called if present at the beginning
        of the new run.

        @param evt    event data object
        @param env    environment object
        """
        logging.info( "pyana_esort_mpl.beginrun() called ")

        print "beginrun is done, starting timer..."
        self.start = time.clock()


    def begincalibcycle( self, evt, env ) :
        """This optional method is called if present at the beginning
        of the new calibration cycle.

        @param evt    event data object
        @param env    environment object
        """
        logging.info( "pyana_esort_mpl.begincalibcycle() called ")


    def event( self, evt, env ) :
        """This method is called for every L1Accept transition.

        @param evt    event data object
        @param env    environment object
        """
        logging.info( "pyana_esort_mpl.event() called ")

        self.nev+=1

        shotEnergy = evt.getFeeGasDet()
        energy = 0.0
        bin = 0
        if shotEnergy is None :
            print "No Gas Detector"
        else :
            energy = (shotEnergy[2]+shotEnergy[3])/2

        acqData = evt.getAcqValue(self.source, 0, env)
        if acqData :
            awf = acqData.waveform()

            if self.ts is None :
                self.ts = acqData.timestamps()

            # average waveform
            if self.wf is None:
                self.wf = awf
                self.wf2 = (awf*awf)
            else :
                self.wf += awf
                self.wf2 += (awf*awf)

            # binned waveform
            bin = int( ((energy-self.emin)/(self.emax-self.emin))*self.nebins+0.5)
            if bin < 1 : bin = 0
            if bin > self.nebins : bin = self.nebins-1
            self.arrayEnrg[bin] += 1

            if self.bwf[bin] is None :
                self.bwf[bin]=awf
                self.bwf2[bin]=(awf*awf)
            else :
                self.bwf[bin]+=awf
                self.bwf2[bin]+=(awf*awf)

    def endcalibcycle( self, env ) :
        """This optional method is called if present at the end of the
        calibration cycle.

        @param env    environment object
        """

        logging.info( "pyana_esort_mpl.endcalibcycle() called" )

    def endrun( self, env ) :
        """This optional method is called if present at the end of the run.

        @param env    environment object
        """
        logging.info( "pyana_esort_mpl.endrun() called" )

    def endjob( self, env ) :
        """This method is called at the end of the job. It should do
        final cleanup, e.g. close all open files.

        @param env    environment object
        """
        logging.info( "pyana_esort_mpl.endjob() called" )

        # have collected the sum so far, but we
        # want to display the average

        self.wf = self.wf / self.nev
        self.wf2 = self.wf2 / self.nev
        self.wf_rms = np.sqrt( self.wf2 - self.wf*self.wf ) / np.sqrt(self.nev)

        self.bwf_rms = []
        for bin in range (0, self.nebins):
            if self.bwf[bin] is None:
                self.bwf_rms.append(None)
                continue

            self.bwf[bin] = self.bwf[bin] / self.arrayEnrg[bin]
            self.bwf2[bin] = self.bwf2[bin] / self.arrayEnrg[bin]
            self.bwf_rms.append(np.sqrt( self.bwf2[bin] \
                                         - self.bwf[bin]*self.bwf[bin] ) \
                                / np.sqrt(self.arrayEnrg[bin]))

        duration = time.clock() - self.start
        print "duration in seconds : ", duration
        print "nevents processed: ", self.nev
        duration = time.clock() - self.start
        print "duration in seconds : ", duration
        print "nevents processed: ", self.nev

        # save "histograms" to an hdf5 file
        ofile = h5py.File("outputfile.hdf5", 'w') # open for writing (overwrites existing file)
        group = ofile.create_group("HistogramArrays")
        group.create_dataset("wf_time",data=self.ts)
        group.create_dataset("wf_avg",data=self.wf)
        group.create_dataset("wf_avg_rms",data=self.wf_rms)
        group.create_dataset("bin_enrg",data=self.arrayEnrg)
        group.create_dataset("bin_axis",data=self.axisEnrg)
        for bin in range (0, self.nebins):
            if self.bwf[bin] is not None:
                group.create_dataset("wf_bin%d"%bin,data=self.bwf[bin])
                group.create_dataset("wf_bin%d_rms"%bin,data=self.bwf_rms[bin])
        ofile.close()


        duration = time.clock() - self.start
        print "duration till after save hdf5, in seconds : ", duration
        # plot
        fig = plt.figure(num=100, figsize=(7.5,5))
        ax = fig.add_subplot(111)
        plt.plot(self.axisEnrg, self.arrayEnrg, 'bo')
        plt.errorbar(self.axisEnrg, self.arrayEnrg, xerr=self.bwidth, yerr=np.sqrt(self.arrayEnrg),fmt=None)
        plt.title("Energy Bins")
        plt.xlabel("Energy")
        plt.ylabel("Event count")
        plt.draw()
        print "energy histogram plotted"
        fig.savefig("pyana_mpl_histEnrg.png")
        print "energy histogram saved"


        fig = plt.figure(num=200, figsize=(7.5,5))
        ax = fig.add_subplot(111)
        plt.clf()
        plt.errorbar(self.ts, self.wf,yerr=self.wf_rms, mew=0.0)
        plt.title("Average Waveform")
        plt.xlabel("time   [s]")
        plt.ylabel("voltage   [V]")
        plt.draw()
        print "wf avg histogram plotted"
        fig.savefig("pyana_mpl_profWfAll.png")
        print "wf avg histogram saved"

        for bin in range (0, self.nebins):
            if self.bwf[bin] is not None:
                # plot
                fig = plt.figure(num=300+bin, figsize=(7.5,5))
                ax = fig.add_subplot(111)
                plt.clf()
                plt.errorbar(self.ts, self.bwf[bin], yerr=self.bwf_rms[bin],mew=0.0)
                plt.title("Waveform bin %d (%.2f<E<%.2f)"\
                          % (bin, self.emin+bin*self.bwidth, self.emin+(bin+1)*self.bwidth))
                plt.xlabel("time    [s]")
                plt.ylabel("voltage    [V]")
                plt.draw()
                print "wf bin %d histogram plotted"%bin
                fig.savefig("pyana_mpl_profWf%d.png"%bin)
                print "wf bin %d histogram saved"%bin


        duration = time.clock() - self.start
        print "duration3 in seconds : ", duration

        # test
        print self.wf.size
        for bin in range (20,40):
            print self.wf[bin], " +-- ", self.wf_rms[bin]

Card

Deck of Cards