source: JEM-EUSO/esaf_cc_at_lal/packages/simulation/detector/electronics/src/Photomultiplier.cc @ 114

Last change on this file since 114 was 114, checked in by moretto, 11 years ago

actual version of ESAF at CCin2p3

File size: 9.9 KB
Line 
1// implementation for class Photomultiplier
2// M. Pallavicini
3//
4#include "Photomultiplier.hh"
5#include "PmtGeometry.hh"
6#include "FrontEndChip.hh"
7#include "MacroCell.hh"
8#include <unistd.h>
9#include <math.h>
10#include <iostream>
11#include "Config.hh"
12#include "EsafRandom.hh"
13#include "EEvent.hh"
14#include "Etypes.hh"
15#include "EusoMapping.hh"
16#include "EDetectorPhotonAdder.hh"
17#include "EusoElectronics.hh"
18#include "EusoDetector.hh"
19#include "EConst.hh"
20
21ClassImp(Photomultiplier)
22
23Double_t Photomultiplier::fgQuantum = 0;           // quantum efficiency
24Double_t Photomultiplier::fgGain = 0;              // nominal gain
25Double_t Photomultiplier::fgGainSigma = 0;         // gain spread
26Double_t Photomultiplier::fgWidth = 0;             // time width
27Double_t Photomultiplier::fgDarkNoiseRate = 0;     // dark noise rate
28Double_t Photomultiplier::fgGtuLength = 0;         // gtu length in ns
29
30//______________________________________________________________________________
31Photomultiplier::Photomultiplier(Int_t id, PmtGeometry* g ): fId(id),
32    fFrontEnd(NULL), fGeometry(g), fCell(NULL), fEC(NULL) {
33    //
34    // Constructor
35    //
36
37    Geometry()->SetPmt( this );
38
39
40    SetState(kPmtIdle);
41    SetEmpty( true );
42
43    if ( fgQuantum == 0 ) {
44        fgQuantum = Conf()->GetNum("Photomultiplier.PmtQuantum");
45        fgGain = Conf()->GetNum("Photomultiplier.PmtGain");
46        fgGainSigma = Conf()->GetNum("Photomultiplier.PmtGainSigma");
47        fgWidth = Conf()->GetNum("Photomultiplier.PmtTimeWidth");
48        fgDarkNoiseRate = Conf()->GetNum("Photomultiplier.fDarkNoiseRate")/sou::microsecond;
49        fgGtuLength = Config::Get()->GetCF("Electronics","MacroCell")->GetNum("MacroCell.fGtuTimeLength");
50    }
51}
52
53
54//______________________________________________________________________________
55Photomultiplier::~Photomultiplier() {
56    //
57    // Destructor
58    //
59
60    SafeDelete(fGeometry);
61    ClearMemory();
62}
63
64//______________________________________________________________________________
65Bool_t Photomultiplier::ClearMemory() {
66    //
67    // Physically release the memory allocated by the arrays of this object
68    //
69
70    // The frontend holds a list of pointers to the vectors of pmt signals.
71    // They are going to be deleted and the pointers to be invalid. The
72    // frontend must be reseted
73    FrontEnd()->Reset();
74
75    map<Int_t, vector<PmtSignal*>* >::const_iterator itVSig;
76
77    for(itVSig=fPmtHits.begin(); itVSig != fPmtHits.end(); itVSig++)  {
78        delete itVSig->second;
79    }
80
81    fPmtHits.clear();
82
83
84
85    return kTRUE;
86
87}
88
89//______________________________________________________________________________
90void Photomultiplier::Reset() {
91    // Reset pmt and get ready for next event list are deleted
92    // PmtSignal objects are deleted by Front End
93
94
95    map<Int_t, vector<PmtSignal*>* >::const_iterator itVSig;
96    vector<PmtSignal*>::const_iterator itSig;
97
98    for(itVSig=fPmtHits.begin(); itVSig != fPmtHits.end(); itVSig++)  {
99        if( itVSig->second ) {
100            vector<PmtSignal*>* ptrVSig = itVSig->second;
101            for(itSig = ptrVSig->begin(); itSig != ptrVSig->end(); itSig++)
102                delete *itSig ;
103
104            ptrVSig->clear();
105
106        }
107    }
108//    for ( Int_t ch=0; ch < Geometry()->NumPads(); ch++ ) {
109//        if ( fPmtHits[ch] ) {
110//            fPmtHits[ch]->clear();
111//        }
112//    }
113    SetState(kPmtIdle);
114    fStartTime = HUGE;
115    fEndTime = -HUGE;
116    SetEmpty( true );
117}
118
119
120//______________________________________________________________________________
121void Photomultiplier::ResetClass() {
122    //
123    // Reset static members of the class
124    //
125
126    fgQuantum = 0;
127    fgGain = 0;
128    fgGainSigma = 0;
129    fgWidth = 0;
130    fgGtuLength = 0;
131}
132
133//______________________________________________________________________________
134Int_t Photomultiplier::FEChannel(Int_t n) {
135    //
136    // Returns front end channel number corresponding to pmt channel n
137    //
138
139    if ( isValid(n) )
140        return fFeMap[n];
141    else
142        return -1;
143}
144
145//______________________________________________________________________________
146ChannelUniqueId Photomultiplier::GetUniqueId(Int_t ch) const {
147    //
148    // Returns channel unique id if the channel belongs to this pmt
149    //
150
151    if ( isValid(ch))
152        return Geometry()->GetUniqueId(ch);
153    else
154        MsgForm(EsafMsg::Panic, "Photomultiplier: %d out of range",ch);
155        return -1;
156}
157
158//______________________________________________________________________________
159void Photomultiplier::SetFrontEnd( FrontEndChip* fe, Int_t row, Int_t col ) {
160    //
161    // Re-assign a new front end chip to this pmt
162    //
163
164    if ( fe == NULL ) {
165        Msg(EsafMsg::Warning) << "NULL front end pointer in Photomultiplier::SetFrontEnd()" << MsgDispatch;
166        return;
167    }
168    if ( fFrontEnd ) {
169        Msg(EsafMsg::Warning)  << "Front End Chip " << fFrontEnd->Id()
170            << " will be destroyed in Photomultiplier::SetFrontEnd()" << MsgDispatch;
171        delete fFrontEnd;
172    }
173    fFrontEnd = fe;
174    BuildFrontEndMap(row, col);
175}
176
177//______________________________________________________________________________
178void Photomultiplier::BuildFrontEndMap( Int_t row, Int_t col) {
179    // Connection between PMT channels and Front-End channels
180    // this is non trivial where a single front end chip reads more than one PMT
181    // the other possibility (pmt channels exceeding fe channels) is not implemented
182
183    Int_t r,c;
184
185    for ( Int_t i=0; i<Geometry()->NumPads(); i++) {
186        r = row+(i / Geometry()->Rows());
187        c = col+(i % Geometry()->Rows());
188
189        if ( fFrontEnd->ChanRowCol(r,c) < FrontEnd()->Channels() ) {
190
191            fFeMap[i] = fFrontEnd->ChanRowCol(r,c);
192
193        } else {
194            Msg(EsafMsg::Warning) << "FE Channels: " << FrontEnd()->Channels() << MsgDispatch;
195            Msg(EsafMsg::Warning) << "Pmt Channels: " << Geometry()->NumPads() << MsgDispatch;
196            Msg(EsafMsg::Warning) << "Current channel row, col: " << r <<","<< c << MsgDispatch;
197            Msg(EsafMsg::Warning) << "Probable mismatch between PMT and FE types"<< MsgDispatch;
198            Msg(EsafMsg::Panic) << "Bad PMT-Front End Mapping" << MsgDispatch;
199        }
200    }
201}
202//
203//______________________________________________________________________________
204void Photomultiplier::AddTest(Double_t tm, Int_t ch) {
205    // Add method for testing purpose only
206    // private; only ElecTestDetTransManager can call it
207
208    TRandom* rndm = EsafRandom::Get();
209
210    // compute charge
211    Double_t delta = fgGainSigma * rndm->Gaus();
212    Double_t charge = fgGain + delta;
213    if ( charge < 0. ) charge = 0.;
214    charge *= EConst::ElectronCharge();   // coulomb
215
216    // create the list if this does not exist
217    if ( fPmtHits[ch] == NULL ) {
218        fPmtHits[ch] = new vector<PmtSignal*>;
219    }
220
221    // create the PmtSignal and add it to the list
222    PmtSignal* sig = new PmtSignal(tm,charge,fgWidth,GetUniqueId(ch),ch+1);
223    fPmtHits[ch]->push_back( sig );
224
225    SetState(kPmtFilling);
226
227    // keep memory of the time interval of this event
228    if ( sig->Time() > fEndTime )
229        fEndTime = sig->Time();
230    if ( sig->Time() < fStartTime )
231        fStartTime = sig->Time();
232
233    SetEmpty( false );
234}
235
236//______________________________________________________________________________
237Bool_t Photomultiplier::Add(Photon& ph) {
238    //
239    // add a photon hit to be simulated
240    //
241    // check if this photon hits this pmt
242    if (!Geometry()->IsInside( ph )) {
243        TVector3 r = (ph.pos-Geometry()->Position()) ;
244        Double_t x = r.Dot(Geometry()->GetX());
245        Double_t y = r.Dot(Geometry()->GetY());
246        Double_t z = r.Dot(Geometry()->GetZ());
247        Printf("Wrong ph. DIFF=(%.3e, %.3e, %.3e)  PROJ=(%.3e, %.3e, %.3e)",
248                r[0], r[1], r[2], x, y, z);
249        return false;
250    }
251
252    // get the channel number
253    Int_t ch = Geometry()->Pad(ph);
254
255    // negative if Photon is lost for geometrical reasons (dead spaces)
256    if ( ch < 0 ) return false;
257
258    // saving pixel id on the photon
259    ph.pixelUid = GetUniqueId(ch);
260
261    // if required, do association mapping between original
262    // theta phi in field of view and this channel
263    //FIXME: EusoMapping::Get()->Associate(this,ch,ph);
264
265    // if signal simulation is disabled, stop here
266    if ( !(GetEusoElectronics()->GetSimulationStatus()) ) return true;
267
268    TRandom* rndm = EsafRandom::Get();
269
270    // handle quantum efficiency
271    Double_t shot = rndm->Rndm();
272
273    if ( shot > fgQuantum )
274        return false;
275
276    // compute charge
277    Double_t delta = fgGainSigma * rndm->Gaus();
278    Double_t charge = fgGain + delta;
279    charge *= EConst::ElectronCharge();
280
281    // create the list if this does not exist
282    if ( fPmtHits[ch] == NULL ) {
283        fPmtHits[ch] = new vector<PmtSignal*>;
284    }
285
286    // create the PmtSignal and add it to the list
287    PmtSignal* sig = new PmtSignal(ph.time,charge,fgWidth,GetUniqueId(ch),ch+1);
288    fPmtHits[ch]->push_back( sig );
289
290    SetState(kPmtFilling);
291
292    ph.madeSignal = true;
293
294    // add this level of information to photon history in root file
295    if ( EEvent::GetCurrent() ) {
296        EDetectorPhotonAdder a(&ph,sig,false);
297        EEvent::GetCurrent()->Fill(a);
298    }
299
300    // keep memory of the time interval of this event
301    if ( sig->Time() > fEndTime )
302        fEndTime = sig->Time();
303    if ( sig->Time() < fStartTime )
304        fStartTime = sig->Time();
305
306    SetEmpty( false );
307
308    return true;
309}
310
311//______________________________________________________________________________
312void Photomultiplier::Simulate() {
313    // Add PmtHits to the Front-End chip
314    // the Photomultipliers job ends here. The Front End simulation
315    // and MacroCell simulation is assumed to be handled by some one else.
316
317    // do not do it twice or if empty
318    if ( Status() != kPmtFilling)
319        return;
320
321    // loop on all channels
322    for( Int_t ch=0; ch<Geometry()->NumPads(); ch++) {
323        if ( fPmtHits[ch] )
324            FrontEnd()->Add( fPmtHits[ch]  , fFeMap[ch] );
325    }
326
327    // set the status to the right value
328    SetState(kPmtDone);
329}
Note: See TracBrowser for help on using the repository browser.