source: trunk/Mars/msimcamera/MSimCamera.cc@ 17878

Last change on this file since 17878 was 17844, checked in by tbretz, 11 years ago
Adapted rc-option naming to MARS convention.
File size: 15.1 KB
Line 
1/* ======================================================================== *\
2!
3! *
4! * This file is part of CheObs, the Modular Analysis and Reconstruction
5! * Software. It is distributed to you in the hope that it can be a useful
6! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
7! * It is distributed WITHOUT ANY WARRANTY.
8! *
9! * Permission to use, copy, modify and distribute this software and its
10! * documentation for any purpose is hereby granted without fee,
11! * provided that the above copyright notice appears in all copies and
12! * that both that copyright notice and this permission notice appear
13! * in supporting documentation. It is provided "as is" without express
14! * or implied warranty.
15! *
16!
17!
18! Author(s): Thomas Bretz, 1/2009 <mailto:tbretz@phys.ethz.ch>
19!
20! Copyright: CheObs Software Development, 2000-2013
21!
22!
23\* ======================================================================== */
24
25//////////////////////////////////////////////////////////////////////////////
26//
27// MSimCamera
28//
29// This task initializes the analog channels with analog noise and simulated
30// the analog pulses from the photon signal.
31//
32// Input Containers:
33// MPhotonEvent
34// MPhotonStatistics
35// MRawRunHeader
36//
37// Output Containers:
38// MAnalogChannels
39//
40//////////////////////////////////////////////////////////////////////////////
41#include "MSimCamera.h"
42
43#include <TF1.h>
44#include <TRandom.h> // Needed for TRandom
45
46#include "MLog.h"
47#include "MLogManip.h"
48
49#include "MTruePhotonsPerPixelCont.h"
50
51#include "MSpline3.h"
52#include "MParSpline.h"
53
54#include "MParList.h"
55
56#include "MPhotonEvent.h"
57#include "MPhotonData.h"
58
59#include "MPedestalCam.h"
60#include "MPedestalPix.h"
61
62#include "MAnalogSignal.h"
63#include "MAnalogChannels.h"
64
65#include "MParameters.h"
66
67#include "MMcEvt.hxx" // To be replaced by a CheObs class
68#include "MRawRunHeader.h"
69
70ClassImp(MSimCamera);
71
72using namespace std;
73
74// --------------------------------------------------------------------------
75//
76// Default Constructor.
77//
78MSimCamera::MSimCamera(const char* name, const char *title)
79 : fEvt(0), fStat(0), fRunHeader(0), fElectronicNoise(0), fGain(0),
80 fCamera(0), fMcEvt(0),fCrosstalkCoeffParam(0), fSpline(0), fBaselineGain(kFALSE),
81 fDefaultOffset(-1), fDefaultNoise(-1), fDefaultGain(-1), fACFudgeFactor(0),
82 fACTimeConstant(0)
83
84{
85 fName = name ? name : "MSimCamera";
86 fTitle = title ? title : "Task to simulate the electronic noise and to convert photons into pulses";
87}
88
89// --------------------------------------------------------------------------
90//
91// Search for the necessayr parameter containers.
92// Setup spline for pulse shape.
93//
94Int_t MSimCamera::PreProcess(MParList *pList)
95{
96 fMcEvt = (MMcEvt*)pList->FindCreateObj("MMcEvt");
97 if (!fMcEvt)
98 return kFALSE;
99
100 fCamera = (MAnalogChannels*)pList->FindCreateObj("MAnalogChannels");
101 if (!fCamera)
102 return kFALSE;
103
104 fEvt = (MPhotonEvent*)pList->FindObject("MPhotonEvent");
105 if (!fEvt)
106 {
107 *fLog << err << "MPhotonEvent not found... aborting." << endl;
108 return kFALSE;
109 }
110
111 fStat = (MPhotonStatistics*)pList->FindObject("MPhotonStatistics");
112 if (!fStat)
113 {
114 *fLog << err << "MPhotonStatistics not found... aborting." << endl;
115 return kFALSE;
116 }
117
118 fRunHeader = (MRawRunHeader *)pList->FindObject("MRawRunHeader");
119 if (!fRunHeader)
120 {
121 *fLog << err << "MRawRunHeader not found... aborting." << endl;
122 return kFALSE;
123 }
124/*
125 fPulsePos = (MParameterD*)pList->FindObject("IntendedPulsePos", "MParameterD");
126 if (!fPulsePos)
127 {
128 *fLog << err << "IntendedPulsePos [MParameterD] not found... aborting." << endl;
129 return kFALSE;
130 }
131 */
132
133 // Create it here to make sure that MGeomApply will set the correct size
134 fElectronicNoise = (MPedestalCam*)pList->FindCreateObj("MPedestalCam", "ElectronicNoise");
135 if (!fElectronicNoise)
136 return kFALSE;
137
138 fGain = (MPedestalCam*)pList->FindCreateObj("MPedestalCam", "Gain");
139 if (!fGain)
140 return kFALSE;
141
142 fAccidentalPhotons = (MPedestalCam*)pList->FindObject("AccidentalPhotonRates","MPedestalCam");
143 if(!fAccidentalPhotons)
144 {
145 *fLog << err << "AccidentalPhotonRates [MPedestalCam] not found... aborting." << endl;
146 return kFALSE;
147 }
148
149 fCrosstalkCoeffParam = (MParameterD*)pList->FindCreateObj("MParameterD","CrosstalkCoeffParam");
150 if (!fCrosstalkCoeffParam)
151 {
152 *fLog << err << "CrosstalkCoeffParam [MParameterD] not found... aborting." << endl;
153 return kFALSE;
154 }
155
156 fTruePhotons = (MTruePhotonsPerPixelCont*)pList->FindCreateObj("MTruePhotonsPerPixelCont");
157 if (!fTruePhotons)
158 {
159 *fLog << err << "MTruePhotonsPerPixelCont not found... aborting." << endl;
160 return kFALSE;
161 }
162
163 MParSpline *pulse = (MParSpline*)pList->FindObject("PulseShape", "MParSpline");
164 if (!pulse)
165 {
166 *fLog << err << "PulseShape [MParSpline] not found... aborting." << endl;
167 return kFALSE;
168 }
169
170// if (fRunHeader->GetFreqSampling()!=1000)
171// {
172// *fLog << err << "ERROR - Sampling frequencies others than 1GHz are not yet supported." << endl;
173// *fLog << warn << "FIXME - SCALE MPulsShape WITH THE SAMPLING FREQUENCY." << endl;
174// return kFALSE;
175// }
176
177 fSpline = pulse->GetSpline();
178 if (!fSpline)
179 {
180 *fLog << err << "No spline initialized." << endl;
181 return kFALSE;
182 }
183
184 // ---------------- Information output ----------------------
185
186 if (fBaselineGain)
187 *fLog << inf << "Gain is also applied to the electronic noise." << endl;
188
189 return kTRUE;
190}
191
192// --------------------------------------------------------------------------
193//
194// FIXME: For now this is a workaround to set a baseline and the
195// electronic (guassian noise)
196//
197Bool_t MSimCamera::ReInit(MParList *plist)
198{
199 for (int i=0; i<fElectronicNoise->GetSize(); i++)
200 {
201 MPedestalPix &ped = (*fElectronicNoise)[i];
202 ped.SetPedestal(fDefaultOffset);
203 if (fDefaultNoise>0)
204 ped.SetPedestalRms(fDefaultNoise);
205
206 ped.SetPedestalABoffset(0);
207 ped.SetNumEvents(0);
208
209
210 MPedestalPix &gain = (*fGain)[i];
211 if (fDefaultGain>0)
212 gain.SetPedestal(fDefaultGain);
213
214 gain.SetPedestalRms(0);
215 gain.SetPedestalABoffset(0);
216 gain.SetNumEvents(0);
217 }
218
219 return kTRUE;
220}
221
222// --------------------------------------------------------------------------
223//
224// fStat->GetMaxIndex must return the maximum index possible
225// (equiv. number of pixels) not just the maximum index stored!
226//
227Int_t MSimCamera::Process()
228{
229 // Calculate start time, end time and corresponding number of samples
230 const Double_t freq = fRunHeader->GetFreqSampling()/1000.;
231
232 // FIXME: Should we use a higher sampling here?
233
234 const Double_t start = fStat->GetTimeFirst()*freq;
235 const Double_t end = fStat->GetTimeLast() *freq;
236
237 const UInt_t nlen = TMath::CeilNint(end-start);
238
239 // Get number of pixels/channels
240 const UInt_t npix = fStat->GetMaxIndex()+1;
241
242 if (npix>(UInt_t)fElectronicNoise->GetSize())
243 {
244 *fLog << err << "ERROR - More indices (" << npix << ") ";
245 *fLog << "assigned than existing in camera (";
246 *fLog << fElectronicNoise->GetSize() << ")!" << endl;
247 return kERROR;
248 }
249
250 const Double_t pl = fSpline->GetXmin()*freq;
251 const Double_t pr = fSpline->GetXmax()*freq;
252
253 // Init the arrays and set the range which will contain valid data
254 fCamera->Init(npix, nlen);
255 fCamera->SetValidRange(TMath::FloorNint(pr), TMath::CeilNint(nlen+pl));
256
257 // Add electronic noise to empty channels
258 for (UInt_t i=0; i<npix; i++)
259 {
260 const MPedestalPix &pix = (*fElectronicNoise)[i];
261
262 const Double_t val = pix.GetPedestal();
263 const Double_t rms = pix.GetPedestalRms();
264
265 // FTemme: Implementation of AC-coupling:
266 // to calculate the value of the accoupling per slice I use the
267 // following equation:
268 // accouplingPerSlice = accidentalPhotonRate * (1 + crossTalkProb)
269 // * areaOfOnePulse / samplingRate;
270 // Therefore I need the following variables
271 // Double_t accidentalPhotonRate; // [MHz]
272 // Float_t crossTalkProb; // [1]
273 // Double_t areaOfOnePulse; // [ADC-Counts * s]
274 // Double_t samplingRate; // [slices * MHz]
275
276 // The accidental photon rate is stored in GHz, so we have to multiply
277 // with 1E3 to get MHz:
278 const MPedestalPix &accPhoPix = (*fAccidentalPhotons)[i];
279
280 const Double_t accidentalPhotonRate = accPhoPix.GetPedestal() * 1e3; //[MHz]
281
282 Double_t currentAccidentalPhotonRate = accidentalPhotonRate;
283 if (fACTimeConstant!=0)
284 {
285 const Double_t accidentalPhotons = fACTimeConstant * accidentalPhotonRate;
286 const Double_t sigmaAccidentalPhotons = TMath::Sqrt(accidentalPhotons);
287
288 const Double_t gaus = gRandom->Gaus(accidentalPhotons,sigmaAccidentalPhotons);
289
290 currentAccidentalPhotonRate = gaus / fACTimeConstant;
291 }
292
293 // Get the CrosstalkCoefficient Parameter
294 const Double_t crossTalkProb = fCrosstalkCoeffParam->GetVal();
295
296 // To get the area of one Pulse, I only need to calculate the Integral
297 // of the Pulse Shape, which is stored in fSpline. Because the spline is
298 // normalized to a maximal amplitude of 1.0, I had to multiply it with
299 // the Default gain [ADC-Counts * s]
300 const Double_t areaOfOnePulse = fSpline->Integral() * fDefaultGain;
301
302 // The sampling rate I get from the RunHeader:
303 const Double_t samplingRate = fRunHeader->GetFreqSampling(); // [slices * MHz]
304
305 const Double_t accouplingPerSlice = currentAccidentalPhotonRate
306 * (1 + crossTalkProb + fACFudgeFactor)
307 * areaOfOnePulse / samplingRate;
308
309 // The accoupling is substracted from the timeline by decreasing the
310 // mean of the gaussian noise which is added
311
312 if (!fBaselineGain)
313 {
314 (*fCamera)[i].AddGaussianNoise(rms, val - accouplingPerSlice);
315 continue;
316 }
317 // Sorry, the name "pedestal" is misleading here
318 // FIXME: Simulate gain fluctuations
319 const Double_t gain = (*fGain)[i].GetPedestal();
320
321 // FIXME: We might add the base line here already.
322 // FIXME: How stable is the offset?
323 // FIXME: Should we write a container AppliedGain for MSImTrigger?
324
325 (*fCamera)[i].AddGaussianNoise(rms*gain, (val - accouplingPerSlice)*gain);
326 }
327
328 // FIXME: Simulate correlations with neighboring pixels
329
330 const Int_t num = fEvt->GetNumPhotons();
331
332 // A random shift, uniformely distributed within one slice, to make sure that
333 // the first photon is not always aligned identically with a sample edge.
334 // FIXME: Make it switchable
335 const Float_t rndm = gRandom->Uniform();
336
337 // FIXME: Shell we add a random shift of [0,1] samples per channel?
338 // Or maybe per channel and run?
339
340 Double_t tot = 0;
341
342 for (int i=0 ; i<1440 ; i++)
343 {
344 (*fTruePhotons->cherenkov_photons_weight)[i] = 0;
345 (*fTruePhotons->cherenkov_photons_number)[i] = 0;
346 (*fTruePhotons->cherenkov_arrival_time_mean)[i] = 0;
347 (*fTruePhotons->cherenkov_arrival_time_variance)[i] = 0;
348 (*fTruePhotons->muon_cherenkov_photons_weight)[i] = 0;
349 (*fTruePhotons->muon_cherenkov_photons_number)[i] = 0;
350 (*fTruePhotons->cherenkov_arrival_time_min)[i] = 10000;
351 (*fTruePhotons->cherenkov_arrival_time_max)[i] = 0;
352 (*fTruePhotons->noise_photons_weight)[i] = 0;
353 }
354
355 // Simulate pulses
356 for (Int_t i=0; i<num; i++)
357 {
358 const MPhotonData &ph = (*fEvt)[i];
359
360 const UInt_t idx = ph.GetTag();
361 const Double_t t = (ph.GetTime()-fStat->GetTimeFirst())*freq+rndm;// - fSpline->GetXmin();
362
363 // FIXME: Time jitter?
364 // FIXME: Add additional routing here?
365 // FIMXE: How stable is the gain?
366
367 if (ph.GetPrimary()!=MMcEvt::kNightSky && ph.GetPrimary()!=MMcEvt::kArtificial)
368 {
369 tot += ph.GetWeight();
370 (*fTruePhotons->cherenkov_photons_weight)[idx] += ph.GetWeight();
371 (*fTruePhotons->cherenkov_photons_number)[idx] += 1;
372
373 (*fTruePhotons->cherenkov_arrival_time_mean)[idx] += t;
374 (*fTruePhotons->cherenkov_arrival_time_variance)[idx] += t*t;
375
376 if (ph.GetPrimary()==MMcEvt::kMUON)
377 {
378 (*fTruePhotons->muon_cherenkov_photons_weight)[idx] += ph.GetWeight();
379 (*fTruePhotons->muon_cherenkov_photons_number)[idx] += 1;
380 }
381
382 // find min
383 if (t < (*fTruePhotons->cherenkov_arrival_time_min)[idx] )
384 {
385 (*fTruePhotons->cherenkov_arrival_time_min)[idx] = t;
386 }
387 // find max
388 if (t > (*fTruePhotons->cherenkov_arrival_time_max)[idx] )
389 {
390 (*fTruePhotons->cherenkov_arrival_time_max)[idx] = t;
391 }
392 }
393 else
394 {
395 (*fTruePhotons->noise_photons_weight)[idx] += ph.GetWeight();
396 }
397
398 // Sorry, the name "pedestal" is misleading here
399 // FIXME: Simulate gain fluctuations
400 const Double_t gain = (*fGain)[idx].GetPedestal();
401
402 // === FIXME === FIXME === FIXME === Frequency!!!!
403 (*fCamera)[idx].AddPulse(*fSpline, t, ph.GetWeight()*gain);
404 }
405
406 for (unsigned int i=0 ; i < 1440 ; i++)
407 {
408 float number = (*fTruePhotons->cherenkov_photons_number)[i];
409 (*fTruePhotons->cherenkov_arrival_time_mean)[i] /= number;
410 float mean = (*fTruePhotons->cherenkov_arrival_time_mean)[i];
411 float sum_tt = (*fTruePhotons->cherenkov_arrival_time_variance)[i];
412 (*fTruePhotons->cherenkov_arrival_time_variance)[i] = (sum_tt / number - mean*mean) /(number - 1);
413 }
414
415 fMcEvt->SetPhotElfromShower(TMath::Nint(tot));
416
417 return kTRUE;
418}
419
420// --------------------------------------------------------------------------
421//
422// BaselineGain: Off
423//
424Int_t MSimCamera::ReadEnv(const TEnv &env, TString prefix, Bool_t print)
425{
426 Bool_t rc = kFALSE;
427 if (IsEnvDefined(env, prefix, "BaselineGain", print))
428 {
429 rc = kTRUE;
430 fBaselineGain = GetEnvValue(env, prefix, "BaselineGain", fBaselineGain);
431 }
432
433 if (IsEnvDefined(env, prefix, "DefaultOffset", print))
434 {
435 rc = kTRUE;
436 fDefaultOffset = GetEnvValue(env, prefix, "DefaultOffset", fDefaultOffset);
437 }
438 if (IsEnvDefined(env, prefix, "DefaultNoise", print))
439 {
440 rc = kTRUE;
441 fDefaultNoise = GetEnvValue(env, prefix, "DefaultNoise", fDefaultNoise);
442 }
443 if (IsEnvDefined(env, prefix, "DefaultGain", print))
444 {
445 rc = kTRUE;
446 fDefaultGain = GetEnvValue(env, prefix, "DefaultGain", fDefaultGain);
447 }
448 if (IsEnvDefined(env, prefix, "ACFudgeFactor", print))
449 {
450 rc = kTRUE;
451 fACFudgeFactor = GetEnvValue(env, prefix, "ACFudgeFactor", fACFudgeFactor);
452 }
453 if (IsEnvDefined(env, prefix, "ACTimeConstant", print))
454 {
455 rc = kTRUE;
456 fACTimeConstant = GetEnvValue(env, prefix, "ACTimeConstant", fACTimeConstant);
457 }
458
459 return rc;
460}
Note: See TracBrowser for help on using the repository browser.