1  #ifndef MARS_MAvalanchePhotoDiode


2  #define MARS_MAvalanchePhotoDiode


3 


4  #ifndef ROOT_TH2


5  #include <TH2.h>


6  #endif


7 


8  #ifndef ROOT_TSortedList


9  #include <TSortedList.h>


10  #endif


11 


12  class Afterpulse : public TObject


13  {


14  private:


15  UInt_t fCellIndex; // Index of GAPD cell the afterpulse belongs to


16 


17  Float_t fTime; // Time at which the afterpulse avalanch broke through


18  Float_t fAmplitude; // Amplitude (crosstalk!) the pulse produced


19 


20  Int_t Compare(const TObject *obj) const


21  {


22  return static_cast<const Afterpulse*>(obj)>fTime>fTime ? 1 : 1;


23  }


24 


25  Bool_t IsSortable() const { return kTRUE; }


26 


27  public:


28  Afterpulse(UInt_t idx, Float_t t) : fCellIndex(idx), fTime(t), fAmplitude(0) { }


29 


30  UInt_t GetCellIndex() const { return fCellIndex; }


31 


32  Float_t GetTime() const { return fTime; }


33  Float_t GetAmplitude() const { return fAmplitude; }


34 


35  Float_t Process(APD &apd)


36  {


37  // Do not process afterpulses twice (e.g. HitRelative + IncreaseTime)


38  // This should not happen anyway


39  // if (fAmplitude>0)


40  // return fAmplitude;


41 


42  const UInt_t nx = apd.GetNumCellsX()+2;


43 


44  const UInt_t x = fCellIndex%nx;


45  const UInt_t y = fCellIndex/nx;


46 


47  fAmplitude = apd.HitCellImp(x, y, fTime);


48 


49  return fAmplitude;


50  }


51  };


52 


53  class APD : public TObject // FIXME: Derive from TH2?


54  {


55  friend class Afterpulse;


56 


57  private:


58  TH2F fHist;


59 


60  TSortedList fAfterpulses; //! List of produced afterpulses


61 


62  Float_t fCrosstalkProb; // Probability that a converted photon creates another one in a neighboring cell


63  Float_t fDeadTime; // Deadtime of a single cell after a hit


64  Float_t fRecoveryTime; // Recoverytime after Deadtime (1exp(t/fRecoveryTime)


65  Float_t fAfterpulseProb[2]; // Afterpulse probabilities


66  Float_t fAfterpulseTau[2]; // Afterpulse time constants


67 


68  Float_t fTime; // A user settable time of the system


69 


70  // The implementation of the cell behaviour (crosstalk and afterpulses)


71  Float_t HitCellImp(Int_t x, Int_t y, Float_t t=0);


72 


73  // Processing of afterpulses


74  void GenerateAfterpulse(UInt_t cell, Int_t idx, Double_t charge, Double_t t);


75  void ProcessAfterpulses(Float_t time, Float_t dt);


76  void DeleteAfterpulses(Float_t time);


77 


78  public:


79  APD(Int_t n, Float_t prob=0, Float_t dt=0, Float_t rt=0);


80 


81  //  Setter and Getter 


82 


83  // Set the afterpulse probability and timeconstant of distribution 1 and 2


84  void SetAfterpulse1(Double_t p, Double_t tau) { fAfterpulseProb[0]=p; fAfterpulseTau[0]=tau; }


85  void SetAfterpulse2(Double_t p, Double_t tau) { fAfterpulseProb[1]=p; fAfterpulseTau[1]=tau; }


86 


87  // Set the afterpulse probability for distribution 1 and 2


88  void SetAfterpulseProb(Double_t p1, Double_t p2) { fAfterpulseProb[0]=p1; fAfterpulseProb[1]=p2; }


89 


90  // Getter functions


91  Float_t GetCellContent(Int_t x, Int_t y) const { return fHist.GetBinContent(x, y); }


92  Int_t GetNumCellsX() const { return fHist.GetNbinsX(); }


93 


94  Float_t GetCrosstalkProb() const { return fCrosstalkProb; }


95  Float_t GetDeadTime() const { return fDeadTime; }


96  Float_t GetRecoveryTime() const { return fRecoveryTime; }


97  Float_t GetTime() const { return fTime; }


98 


99  Float_t GetRelaxationTime(Float_t threshold=0.001) const;


100 


101  Float_t GetLastHit() const { return fHist.GetMaximum(); }


102 


103  TSortedList &GetListOfAfterpulses() { return fAfterpulses; }


104 


105  // Functions for easy production of statistics about the cells


106  Int_t CountDeadCells(Float_t t=0) const;


107  Int_t CountRecoveringCells(Float_t t=0) const;


108 


109  //  Lower level user interface 


110 


111  // Implementation to hit a specified or random cell


112  Float_t HitCell(Int_t x, Int_t y, Float_t t=0);


113  Float_t HitRandomCell(Float_t t=0);


114 


115  // Functions to produce virgin chips or just effected by constant rates


116  void FillEmpty(Float_t t=0);


117  void FillRandom(Float_t rate, Float_t t=0);


118 


119  // Produce random pulses with the given rate over a time dt.


120  // Processes afterpulses until the new time and deletes previous


121  // afterpulses.


122  Float_t Evolve(Double_t freq, Double_t dt);


123 


124  // Delete Afterpulses before fTime. This might be wanted after


125  // a call to Evolve or Relax to maintain memeory usage.


126  void DeleteAfterpulses() { DeleteAfterpulses(fTime); }


127 


128  //  High level user interface 


129 


130  // This fills a GAPD with a rough estimated state at a given time


131  // T=0. It then evolves the time over the ralaxation time. If the


132  // chip is not virgin (i.e. fTime<0) the random filling is omitted


133  void Init(Float_t rate) { if (fTime<0) FillRandom(rate); Relax(rate); ShiftTime(); }


134 


135  // Shifts all times including fTime by dt backwards (adds dt)


136  // This is convenient because you can set the current time (fTime) to 0


137  void ShiftTime(Double_t dt);


138  void ShiftTime() { ShiftTime(fTime); }


139 


140  // Functions producing photons hitting cells. It is meant to add


141  // many photons with an arrival time t after fTime. The photons


142  // must be sorted in time first to ensure proper treatment of the


143  // afterpulses.


144  Float_t HitRandomCellRelative(Float_t t=0) { ProcessAfterpulses(fTime, t); return HitRandomCell(fTime+t); }


145 


146  // Produce random pulses with a given frequency until the influence


147  // of the effects of the GAPD (relaxation time, afterpulses) are


148  // below the given threshold. (Calls Evolve())


149  // FIXME: Maybe the calculation of the relaxation time could be optimized?


150  Float_t Relax(Double_t freq, Float_t threshold=0.001) { return Evolve(freq, GetRelaxationTime(threshold)); }


151 


152  // Issue afterpulses until fTime+dt and set fTime to fTime+dt


153  // This is needed to create all afterpulses from external pulses


154  // and afterpulses until the time fTime+dt. This makes mainly


155  // the list of afterpulses complete until fTime+dt


156  void IncreaseTime(Float_t dt) { ProcessAfterpulses(fTime, dt); fTime += dt; }


157 


158  // TObject


159  void Draw(Option_t *o="") { fHist.Draw(o); }


160  void DrawCopy(Option_t *o="") { fHist.DrawCopy(o); }


161 


162  ClassDef(APD, 1) // An object representing a Geigermode APD


163  };


164 


165  #endif

