BRAT 2.4.5
Class index
Full class index
brahmlib
BRAHMS
ROOT page
//____________________________________________________________________
//
//   The BrTpcDeconvoluteClusterModule used to be part of
//   BrTpcClusterFinder
//
//   It takes clusters sequences that come from BrTpcClusterModule and
//   examines the status. If removes noise clusters and tries to
//   deconvolute multiclusters. 
//   The output data is (also) clusters in the input datatable
//

//____________________________________________________________________
//
// $Id: BrTpcDeconvoluteClusterModule.cxx,v 1.8 2002/08/15 17:23:31 videbaek Exp $
// $Author: videbaek $
// $Date: 2002/08/15 17:23:31 $
// $Copyright: (C) 2001 BRAHMS Collaboration <brahmlib@rhic.bnl.gov>

#ifndef BRAT_BrTpcDeconvoluteClusterModule
#include "BrTpcDeconvoluteClusterModule.h"
#endif

#ifndef ROOT_TObjArray
#include "TObjArray.h"
#endif
#ifndef ROOT_TH1
#include "TH1.h"
#endif
#ifndef ROOT_TDirectory
#include "TDirectory.h"
#endif

#ifndef BRAT_BrParameterDbManager
#include "BrParameterDbManager.h"
#endif
#ifndef BRAT_BrDetectorParamsTPC
#include "BrDetectorParamsTPC.h"
#endif
#ifndef BRAT_BrTableNames
#include "BrTableNames.h"
#endif

#ifndef WIN32
#include <iostream>
#else
#include <iostream.h>
#endif
#include <iomanip.h>

//__________________________________________________________________ 

ClassImp(BrTpcDeconvoluteClusterModule);

//__________________________________________________________________
 BrTpcDeconvoluteClusterModule::BrTpcDeconvoluteClusterModule()
  : BrModule() 
{
  // This constructer is no good
  SetState(kSetup);

  fClusterTable    = 0;
  fAdcTable        = 0;
}

//__________________________________________________________________
 BrTpcDeconvoluteClusterModule::BrTpcDeconvoluteClusterModule(const Char_t *name, 
				       const Char_t *title) 
  : BrModule(name, title)
{
  // This is the constructor that should be used
  // Name should be "T1", "T2", "TPM1", "TPM2"
  SetState(kSetup);

  fClusterTable    = 0;
  fAdcTable        = 0;
  
  // define default cut parameters
  SetHighPsigCut();
  SetHighTsigCut();
  SetMinPadCut(); 
  SetMinTimeCut();
  SetMinMaxADCCut();
}

//_________________________________________________________________
 BrTpcDeconvoluteClusterModule::~BrTpcDeconvoluteClusterModule()
{
  if( fClusterTable ) {
    fClusterTable->Clear();
    delete fClusterTable;
  }

  if(fAdcTable)
    delete fAdcTable;
}

//_______________________________________________________________________
 Bool_t BrTpcDeconvoluteClusterModule::DeconvoluteClusters()
{
  /**************************************************************
   *                                                            *
   *  The purpose of this function is to break up any cluster   *
   *  which has the topology indicating that it might contain   *
   *  information from more than 1 track. Such clusters would   *
   *  have the feature of more than 1 local maxima. (Of course  *
   *  2 tracks could be so close that only 1 maximum results.)  *
   *                                                            *
   *  This is a difficult routine to write but it is very       *
   *  important, especially for HBT pions. For now, I simply    *
   *  fill in a skeleton of how one might approach the problem. *
   *                                                            *
   *  M. Justice                                                *
   *  16-Nov-1999                                               *
   *  It is worth noting it is important for any even modest    *
   *  track densities in the TPC as learned in other methods(fv)*
   *                                                            *
   **************************************************************/

  Int_t nSubClusters = 0;
  Int_t nNoiseClusters = 0;
  Int_t nDeleted = 0;  
  TObjArray subClusters(2); // autoexpands if more than 2 subclusters
  
  const Int_t nEntries = fClusterTable->GetEntries();
  Debug(1,"DeconvoluteClusters"," Table has %d entries", nEntries);
  
  for(Int_t i = 0; i < nEntries; i++) {
    
    subClusters.Clear();
    
    BrTpcCluster *cluster = (BrTpcCluster *)fClusterTable->At(i);
    
    // The next method checks the status of the cluster and
    // deconvolutes if possible It returns number of peaks
    // (=subclusters) and the subclusters in the TObjArray

    Debug(3,"FindSubClusters"," cluster # %d ", i);

    const Int_t nPeaks = FindSubClusters(cluster, &subClusters);
    const Int_t status = cluster->GetStatus();

    if(status == BrTpcCluster::kNoiseHit) {

      Debug(5,"  ","is noisehit");
      // remove and delete the cluster
      fClusterTable->DeleteObjectAt(i);
      nDeleted++;
      nNoiseClusters++;

    } else if (status == BrTpcCluster::kSingleHit) {
      Debug(5,"  ","is singlehit");
      // do nothing

    } else if (status == BrTpcCluster::kMultiHit) {

      Debug(5,"  ","is multihit %d peaks",nPeaks);
      // remove cluster after we added good deconv. clusters
      
      Int_t nP = 0;
      Int_t j = 0;
      for (j = 0; j < nPeaks; j++) {

	BrTpcCluster *jcluster = (BrTpcCluster *)subClusters.At(j);

	// Add jcluster only if not noise
	if (jcluster->GetStatus() != BrTpcCluster::kNoiseHit){
	  
	  // Add jcluster after the last in our loop
	  // wait with compression
	  //	  fClusterTable->AddAt(jcluster, nEntries+nSubClusters); 
	  fClusterTable->Add(jcluster); 
	  nDeleted--;
	  nSubClusters++;
	  nP++;
	} 
	else 
	    delete jcluster; 
      }

      // remove and delete the old cluster
      fClusterTable->DeleteObjectAt(i);
      nDeleted++;
      if(HistOn())
	hNpeaks->Fill(nP);
      
    } else {
      
      // How did we ever get here ?
      Warning("DeconvoluteClusters", "Illegal cluster status");
    }
    
  } 
  
  // Important to remember to compress the table
  fClusterTable->Compress();
  
  if(DebugLevel()>0)
    cout << "Number of final clusters = " 
	 << fClusterTable->GetEntries() << endl;

  if(DebugLevel()>1) {

    cout << "Number of noise clusters = " << nNoiseClusters << endl
	 << "Number of sub clusters   = " << nSubClusters << endl;
  }

  const Int_t n = fClusterTable->GetEntries();
  if(n+nDeleted != nEntries) {
    Warning("deconvolute","values %f %f %f ", nEntries,nDeleted,n);
  }
     // Fill histograms if applicable
  if(HistOn()) {

    hNnoiseclusters->Fill(nNoiseClusters);
    hNsubclusters->Fill(nSubClusters);
    
    const Int_t n = fClusterTable->GetEntries();
    hNclusters->Fill(n);
    
    Int_t i = 0;
    for(i = 0; i < n; i++) {
      
      BrTpcCluster *cluster = (BrTpcCluster *)fClusterTable->At(i);
      hNpads->Fill(cluster->GetNpads());
      hNtime->Fill(cluster->GetNbins());
      hMaxADC->Fill(cluster->GetMaxADC());
      hSumADC->Fill(cluster->GetADCSum());
      hPadvar->Fill(cluster->GetVarPad());
      hTimevar->Fill(cluster->GetVarTime());
    }
  }

  int nEntriesAtEnd = fClusterTable->GetEntries();
  if(DebugLevel()>1)
    cout << "Cluster Table has " << nEntriesAtEnd << endl;
  
  
  return kTRUE;
}

//_______________________________________________________________________
 void BrTpcDeconvoluteClusterModule::DefineHistograms()
{
// Define the histograms used to monitor performance
// This method is usually called by BrModule::Book().
//

  // Initialiser at job level
  if (GetState() != kInit) {
    Stop("DefineHistograms", "Must be called after Init");
    return;
  }

  // Create new subdirectory for histograms
  TDirectory* savdir = gDirectory;
  Char_t Dirname[32];
  sprintf(Dirname,"DeconvoluteCluster_%s",GetName());
  TDirectory* hdir = savdir->mkdir(Dirname);
  
  if (!hdir) {
    Warning("DefineHistograms","Could not create histogram subdirectory");
    return;
  }
  hdir->cd();
  
  Char_t Histname[32];
  Char_t HistTitle[48];
  
  sprintf(Histname,"hNpads_%s",GetName());
  sprintf(HistTitle,"%s: # pads per cluster",GetName());
  hNpads = new TH1F(Histname, HistTitle,20,0.5,20.5);
  hNpads->SetXTitle( "N_{pads}" );
  hNpads->SetYTitle( "dN/dN_{pads}" );
  
  sprintf(Histname,"hNtimebins_%s",GetName());
  sprintf(HistTitle,"%s: # time bins per cluster",GetName());
  hNtime = new TH1F(Histname, HistTitle,20,0.5,20.5);
  hNtime->SetXTitle( "N_{time bins}" );
  hNtime->SetYTitle( "dN/dN_{time bins}" );
  
  sprintf(Histname,"hNclusters_%s",GetName());
  sprintf(HistTitle,"%s: # clusters per event",GetName());
  hNclusters = new TH1F(Histname, HistTitle,800,-0.5,799.5);
  hNclusters->SetXTitle( "N_{clusters}" );
  hNclusters->SetYTitle( "dN/dN_{clusters}" );
  
  sprintf(Histname,"hMaxADC_%s",GetName());
  sprintf(HistTitle,"%s: max ADC in clusters",GetName());
  hMaxADC = new TH1F(Histname, HistTitle,1024,0.5,1024.5);  
  hMaxADC->SetXTitle( "ADC_{max}" );
  hMaxADC->SetYTitle( "dN/dADC_{max}" );
  
  sprintf(Histname, "hSumADC_%s", GetName());
  sprintf(HistTitle, "%s: integrated ADC in clusters", GetName());
  hSumADC = new TH1F(Histname, HistTitle, 1024, 0, 10240);
  hSumADC->SetXTitle( "ADC_{sum}" );
  hSumADC->SetYTitle( "dN/dADC_{sum}" );

  sprintf(Histname,"hPadvar_%s",GetName());
  sprintf(HistTitle,"%s: pad sigma",GetName());
  hPadvar = new TH1F(Histname, HistTitle,40,0.0,10.0);  
  hPadvar->SetXTitle( "#sigma_{pad} [pads]" );
  hPadvar->SetYTitle( "dN/d#sigma_{pad}" );
  
  sprintf(Histname,"hTimevar_%s",GetName());
  sprintf(HistTitle,"%s: time sigma",GetName());
  hTimevar = new TH1F(Histname, HistTitle,40,0.0,10.0);  
  hTimevar->SetXTitle( "#sigma_{time bin} [time bin]" );
  hTimevar->SetYTitle( "dN/d#sigma_{time bin}" );
  
  sprintf(Histname,"hNnoiseclusters_%s",GetName());
  sprintf(HistTitle,"%s: # noise clusters per event",GetName());
  hNnoiseclusters = new TH1F(Histname, HistTitle,800,-0.5,799.5);
  hNnoiseclusters->SetXTitle( "N_{clusters}" );
  hNnoiseclusters->SetYTitle( "dN/dN_{clusters}" );
  
  sprintf(Histname,"hNsubclusters_%s",GetName());
  sprintf(HistTitle,"%s: # good sub clusters per event",GetName());
  hNsubclusters = new TH1F(Histname, HistTitle,800,-0.5,799.5);
  hNsubclusters->SetXTitle( "N_{subclusters}" );
  hNsubclusters->SetYTitle( "dN/dN_{subclusters}" );

  sprintf(Histname,"hNpeaks_%s",GetName());
  sprintf(HistTitle,"%s: # good sub clusters per cluster",GetName());
  hNpeaks = new TH1F(Histname, HistTitle,100,-0.5,99.5);
  hNpeaks->SetXTitle( "N_{subclusters}" );
  hNpeaks->SetYTitle( "dN/dN_{subclusters}" );

  // Restore directory
  savdir->cd();
}

//_________________________________________________________________
void 
 BrTpcDeconvoluteClusterModule::Event(BrEventNode *inputNode, 
				     BrEventNode *outputNode)
{ 
  // Main method
  // Gets the TPCCluster data from the inputNode
  // Examines the status of the clusters and tries to deconvolute
  // multihits 
  // The output is the same table as the input so no new table is
  // appended, i.e, the changes are made to the old table.
  
  SetState(kEvent);

  if(DebugLevel()>0)
    cout << Form("Entering BrTpcDeconvoluteClusterModule (%s) Event()", 
		 GetName()) << endl;
  
  fClusterTable = 
    inputNode->GetDataTable(Form("%s %s", BRTABLENAMES kTPCCluster, GetName()));
  
  if(fClusterTable == 0) {
    
    if(DebugLevel() > 0 ) 
      Warning("Event", "BrDataTable %s %s not found in this event!",
	      BRTABLENAMES kTPCCluster, GetName());
    
    return;
  }
  
  // Check that there are any clusters in the table or the id trick crashes
  const Int_t nEntries = fClusterTable->GetEntries();
  if(nEntries==0)
    return;

  // Set the cluster id to be the id of the last of the clusters in
  // the table + 1
  fClusterId = ((BrTpcCluster*)fClusterTable->
		At((fClusterTable->GetEntries()-1)))->GetID() + 1;

  if(DebugLevel()>2) cout << "Deconvoluting clusters" << endl;
  DeconvoluteClusters(); // also low max ADC clusters are removed
 
  // The data table is still in the event node so no need to add
  // anything 
}
//_______________________________________________________________________
void 
 BrTpcDeconvoluteClusterModule::FillSubClusters(Int_t nPeaks, 
					       TObjArray *subClusters)
{
  //
  // Scan the working array and create a set of subclusters
  // according to the fClusterIdTable identification.
  // The appropriate set of BrTPSequence objects that make up the
  // clusters are created. These are of course NOT the inputdata
  // but a subset.
  // This routine needs access to fCurrentRow, and the next available ClusterId
  // to be used.
  
  for(Int_t peak = 0; peak < nPeaks; peak++) {
    
    BrTpcCluster *cluster = new BrTpcCluster();
    cluster->SetRow(fCurrentRow);
    cluster->SetID(fClusterId++);
    subClusters->Add(cluster);
  }

  //
  // scan each pad and find sequence in this pad.
  //

  const Int_t minPad  = fAdcTable->GetMinPad();
  const Int_t maxPad  = fAdcTable->GetMaxPad() + 1;
  const Int_t minTime = fAdcTable->GetMinTime();
  const Int_t maxTime = fAdcTable->GetMaxTime() + 1;
  
  for (Int_t pad = minPad; pad < maxPad; pad++) {
    
    Int_t timebin = minTime;
    
    while(timebin < maxTime){
      
      // Check that pixel was used
      const Int_t id = fAdcTable->GetId(pad, timebin);
      
      if (id < 1 ){
	
	timebin++;
      } else {
	
	const Int_t firstTimebin = timebin;
	
	// Find the length of the sequence 
	Int_t nSeq = 0;
	while(timebin < maxTime && 
	      fAdcTable->GetId(pad, timebin) == id) {
	  nSeq++; timebin++;
	}
	      
	BrTpcSequence *seq = new BrTpcSequence(nSeq);
	seq->SetPad(pad);
	seq->SetRow(fCurrentRow);
	seq->SetTime(firstTimebin);

	for(Int_t n = 0; n < nSeq; n++) 
	  seq->SetAdc(n, fAdcTable->GetAdc(pad, firstTimebin+n));
	
	if(DebugLevel()>3)
	  cout << "Add seq " <<fCurrentRow<<" " << pad 
	       << " " << firstTimebin << " " << nSeq <<endl;
	
	BrTpcCluster *cluster = 
	  (BrTpcCluster *)subClusters->At(id-1);
	seq->SetClustNum(cluster->GetID());
	
	// Add the sequence to the cluster (and the ownership)
	cluster->AddSeq(*seq, kFALSE);
      }
    }
  }
}

//____________________________________________________________
 void BrTpcDeconvoluteClusterModule::FillWorkingArrays(BrTpcCluster *cluster)
{
  //
  // Fill the adcTable with adc values in prepartion for 
  // subclusterfinding. 
  //

  fCurrentRow    = cluster->GetRow(); // Used when table --> clusters

  const Int_t nSeqs    = cluster->GetNseqs();
  
  for (Int_t j = 0; j < nSeqs; j++) {
    
    BrTpcSequence *jseq     = cluster->GetSeq(j);
    const Int_t pad         = jseq->GetPad();
    const Int_t nbkts       = jseq->GetNseq();
    const Int_t timebin     = jseq->GetTime();
    
    for (Int_t k = 0; k < nbkts; k++) {
      
      fAdcTable->SetAdc(pad, timebin + k, jseq->GetAdc(k));
      fAdcTable->SetId(pad, timebin + k, 0);
    }
  }
  
}

//___________________________________________________________
 Int_t BrTpcDeconvoluteClusterModule::FindHitStatus(BrTpcCluster* cluster)
{
  // Determine the status of each cluster 
  // The outcome can be either 
  // noisehit (throw away)
  // single hit 
  // multi hit (deconvolution needed)
  
  // Apply noise cuts
  if (cluster->GetNpads() <= fMinPadCut ||
      cluster->GetNbins() <= fMinTimeCut ||
      cluster->GetMaxADC()<= fMinMaxADCCut) {
    return (BrTpcCluster::kNoiseHit);
  }
  
  // Check that both widths are small
  if( (cluster->GetVarPad() < fHighPsigCut) && 
      (cluster->GetVarTime() < fHighTsigCut) )
    return (BrTpcCluster::kSingleHit);
  else    return (BrTpcCluster::kMultiHit);
}

//_________________________________________________________________________
Int_t 
 BrTpcDeconvoluteClusterModule::FindSubClusters(BrTpcCluster *primaryCluster,
					       TObjArray *subClusters)
{
  // primaryCluster is scanned with FindHitStatus to determine if its
  // noise, a good single hit cluster or a multihit candidate. The
  // TObjArray is empty initially. Ownership of new BrTpcClusters from
  // deconvolution is transferred to this array on exit.
  //
  // Deconvolution is done as follows :
  // -  Fill working array
  // -  Finds peaks and work towards valleys
  // -  Identify part sequences belonging to same peak
  // -  Create subClusters and new BrTpcSequences for these clusters
  // -  
  //

  Int_t status = FindHitStatus(primaryCluster);
  
  if(status == BrTpcCluster::kSingleHit ||
     status == BrTpcCluster::kNoiseHit) {

    primaryCluster->SetStatus(status);
    return 1;
  }
  
  primaryCluster->SetStatus(BrTpcCluster::kMultiHit);
  
  // Clear the working 2d array
  fAdcTable->Clear();

  // Fill the ADC values into the working array
  FillWorkingArrays(primaryCluster);
  
  // Find Peaks
  const Int_t nPeaks = fAdcTable->FindPeaks(Short_t(fMinMaxADCCut));
  
  // nPeaks should always be greater than 0
  if (nPeaks < 1) {
    
    fAdcTable->Print();
    Stop("DeconvoluteClusters", "Illegal number of peaks");
  }
  
  // Fill the sub clusters corresponding to each peak
  FillSubClusters(nPeaks, subClusters);
  
  // Find and set status of subclusters
  for(Int_t peak = 0;peak < nPeaks; peak++){

    BrTpcCluster *cluster = (BrTpcCluster*) subClusters->At(peak);

    status = FindHitStatus(cluster);

    if(status == BrTpcCluster::kNoiseHit)
      cluster->SetStatus(status);    

    if(status == BrTpcCluster::kSingleHit)
      cluster->SetStatus(BrTpcCluster::kSingleHitDec);
    
    if(status == BrTpcCluster::kMultiHit)
      cluster->SetStatus(BrTpcCluster::kMultiHitDec);
  }
  
  return nPeaks;
}

//_______________________________________________________________________
 void BrTpcDeconvoluteClusterModule::Init() 
{
  // Initialize module. This is the proper member fct for getting
  // information from the data base.
  SetState(kInit);

  BrParameterDbManager* gParamDb = BrParameterDbManager::Instance();
  BrDetectorParamsTPC *params = (BrDetectorParamsTPC*)
    gParamDb->GetDetectorParameters("BrDetectorParamsTPC", GetName());
  
  // set parameters
  const Int_t padsPerRow = params->GetPadsprow();
  const Int_t noBuckets  = params->GetNoBuckets();

  fAdcTable  = new BrTpcAdcTable(padsPerRow, noBuckets);
}

//____________________________________________________________________
 void BrTpcDeconvoluteClusterModule::Print(Option_t* option) const
{ 
  // Module Information method
  //
  // Options: (see also BrModule::Print)
  //  
  BrModule::Print(option);

  TString opt(option);
  opt.ToLower();
  
  if (opt.Contains("d"))
    cout << endl
         << "  Original author: Peter H.L. Christiansen" << endl
         << "  Last Modifications: " << endl
         << "    $Author: videbaek $" << endl 
         << "    $Date: 2002/08/15 17:23:31 $"   << endl
         << "    $Revision: 1.8 $ " << endl 
         << endl
         << "-------------------------------------------------" << endl;

  cout << " highPsigCut  = " << fHighPsigCut  << endl 
       << " highTsigCut  = " << fHighTsigCut  << endl 
       << " minPadCut    = " << fMinPadCut    << endl 
       << " minTimeCut   = " << fMinTimeCut   << endl 
       << " minMaxADCCut = " << fMinMaxADCCut << endl; 
} 

////////////////////////////////////////////////////////////////////////////
//
// $Log: BrTpcDeconvoluteClusterModule.cxx,v $
// Revision 1.8  2002/08/15 17:23:31  videbaek
// Add better diagnostics code.
//
// Revision 1.7  2002/01/03 19:53:19  cholm
// Prepared to use BrTableNames class (or perhaps BrDetectorList) for table names
//
// Revision 1.6  2001/08/16 15:45:17  jens
//
// BrTpcClusterModule
// BrTpcDeconvoluteClusterModule
// BrTpcTrackModule
// Changed some variable names for histograms and the title scheme for histogram.
// Now histograms have title like e.g. "<TPC name>: max ADC in clusters".
//
// BrTpcClusterModule
// Added the possibility to reset sequences in fSeqTable. BrTpcSequence::fClustNum
// is altered in BrTpcClusterModule::FindClusters, and thus made it impossible to
// reanalyze an event. I.e. previously a new instance of BrEvent had to be
// allocated and filled from input.
//
// Revision 1.5  2001/08/14 19:29:33  pchristi
// Changed the Print methods to pass the option to BrModule.
// Also removed debug statement in BrTpcTrackFollowModule.
//
// Revision 1.4  2001/07/17 20:30:50  ejkim
// Fixed bug when number of clusters in input was 0.
//
// Revision 1.3  2001/07/06 10:24:05  pchristi
// Changed assert to the ROOT Assert in TError.h
//
// Revision 1.2  2001/06/22 17:45:19  cholm
// Change names so that every data class has the same format, so that
// we will not have to worry about that later on. The affected classes
// are:
//
//         BrTPCSequence       ->        BrTpcSequence
//         BrTPCCluster        ->        BrTpcCluster
//         BrTPCClusterTable   ->        BrTpcClusterTable
//
// These changes has ofcourse been propegated to the modules as well,
// giving the changes
//
//         BrTPCClusterFinder  ->        BrTpcClusterFinder
//         BrTPCSequenceAdder  ->        BrTpcSequenceAdder
//
// Revision 1.1.1.1  2001/06/21 14:55:13  hagel
// Initial revision of brat2
//
// Revision 1.2  2001/06/17 17:29:36  pchristi
// Near final version. A little cosmetics is still needed.
//
// Revision 1.1  2001/05/29 14:20:26  pchristi
// Initial import of new Tpc classes
//
//

This page automatically generated by script docBrat by Christian Holm

Copyright ; 2002 BRAHMS Collaboration <brahmlib@rcf.rhic.bnl.gov>
Last Update on by

Validate HTML
Validate CSS