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 APD : public TObject // FIXME: Derive from TH2?


13  {


14  friend class Afterpulse;


15 


16  private:


17  TH2F fHist;


18 


19  TSortedList fAfterpulses; //! List of produced afterpulses


20 


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


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


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


24  Float_t fAfterpulseProb[2]; // Afterpulse probabilities


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


26 


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


28 


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


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


31 


32  // Processing of afterpulses


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


34  void ProcessAfterpulses(Float_t time, Float_t dt);


35  void DeleteAfterpulses(Float_t time);


36 


37  public:


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


39 


40  //  Setter and Getter 


41 


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


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


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


45 


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


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


48 


49  // Getter functions


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


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


52 


53  Float_t GetCrosstalkProb() const { return fCrosstalkProb; }


54  Float_t GetDeadTime() const { return fDeadTime; }


55  Float_t GetRecoveryTime() const { return fRecoveryTime; }


56  Float_t GetTime() const { return fTime; }


57 


58  Float_t GetRelaxationTime(Float_t threshold=0.001) const;


59 


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


61 


62  TSortedList &GetListOfAfterpulses() { return fAfterpulses; }


63 


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


65  Int_t CountDeadCells(Float_t t=0) const;


66  Int_t CountRecoveringCells(Float_t t=0) const;


67 


68  //  Lower level user interface 


69 


70  // Implementation to hit a specified or random cell


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


72  Float_t HitRandomCell(Float_t t=0);


73 


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


75  void FillEmpty(Float_t t=0);


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


77 


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


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


80  // afterpulses.


81  Float_t Evolve(Double_t freq, Double_t dt);


82 


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


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


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


86 


87  //  High level user interface 


88 


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


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


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


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


93 


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


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


96  void ShiftTime(Double_t dt);


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


98 


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


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


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


102  // afterpulses.


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


104 


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


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


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


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


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


110 


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


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


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


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


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


116 


117  // TObject


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


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


120 


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


122  };


123 


124  class Afterpulse : public TObject


125  {


126  private:


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


128 


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


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


131 


132  Int_t Compare(const TObject *obj) const


133  {


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


135  }


136 


137  Bool_t IsSortable() const { return kTRUE; }


138 


139  public:


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


141 


142  UInt_t GetCellIndex() const { return fCellIndex; }


143 


144  Float_t GetTime() const { return fTime; }


145  Float_t GetAmplitude() const { return fAmplitude; }


146 


147  Float_t Process(APD &apd)


148  {


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


150  // This should not happen anyway


151  // if (fAmplitude>0)


152  // return fAmplitude;


153 


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


155 


156  const UInt_t x = fCellIndex%nx;


157  const UInt_t y = fCellIndex/nx;


158 


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


160 


161  return fAmplitude;


162  }


163  };


164 


165  #endif

