source: trunk/MagicSoft/Mars/msimcamera/MSimTrigger.cc@ 9462

Last change on this file since 9462 was 9462, checked in by tbretz, 15 years ago
*** empty log message ***
File size: 22.3 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@astro.uni-wuerzburg.de>
19!
20! Copyright: CheObs Software Development, 2000-2009
21!
22!
23\* ======================================================================== */
24
25//////////////////////////////////////////////////////////////////////////////
26//
27// MSimTrigger
28//
29// This task takes the pure analog channels and simulates a trigger
30// electronics.
31//
32// In a first step several channels can be summed together by a look-up table
33// fRouteAC.
34//
35// In a second step from these analog channels the output of a discriminator
36// is calculated using a threshold and optional a fixed digital signal length.
37//
38// The signal length of the digital signal emitted by the discriminator
39// can either be bound to the time the signal is above the threshold
40// defined by fDiscriminatorThreshold if fDigitalSignalLength<0 or set to a
41// fixed length (fDigitalSignalLength>0).
42//
43// With a second look-up table fCoincidenceMap the analog channels are
44// checked for coincidences. The coincidence must at least be of the length
45// defined by fCoincidenceTime. The earliest coincide is then stored as
46// trigger position.
47//
48// If a minimum multiplicity m is given, m signals above threshold
49// in the coincidence patterns are enough to emit a trigger signal.
50//
51//
52// For MAGIC1:
53// - fDigitalSignalLength between 6ns and 12ns
54// - fCoincidenceTime between 0.25ns to 1ns
55//
56//
57// Input Containers:
58// IntendedPulsePos [MParameterD]
59// MAnalogChannels
60// MRawRunHeader
61//
62// Output Containers:
63// TriggerPos [MParameterD]
64// MRawEvtHeader
65//
66//////////////////////////////////////////////////////////////////////////////
67#include "MSimTrigger.h"
68
69#include "MLog.h"
70#include "MLogManip.h"
71
72#include "MParList.h"
73#include "MParameters.h"
74
75#include "MLut.h"
76#include "MArrayI.h"
77
78#include "MRawEvtHeader.h"
79#include "MRawRunHeader.h"
80
81#include "MAnalogSignal.h"
82#include "MAnalogChannels.h"
83#include "MDigitalSignal.h"
84
85#include "MTriggerPattern.h"
86
87#include "MPedestalCam.h"
88#include "MPedestalPix.h"
89
90ClassImp(MSimTrigger);
91
92using namespace std;
93
94// --------------------------------------------------------------------------
95//
96// Default Constructor.
97//
98MSimTrigger::MSimTrigger(const char *name, const char *title)
99 : fCamera(0), fPulsePos(0), fTrigger(0), fRunHeader(0),
100 fEvtHeader(0), fElectronicNoise(0), fGain(0),
101 fDiscriminatorThreshold(-1), fDigitalSignalLength(8), fCoincidenceTime(0.5),
102 fShiftBaseline(kTRUE), fUngainSignal(kTRUE), fSimulateElectronics(kTRUE),
103 fMinMultiplicity(-1)
104{
105 fName = name ? name : "MSimTrigger";
106 fTitle = title ? title : "Task to simulate trigger electronics";
107}
108
109// --------------------------------------------------------------------------
110//
111// Take two TObjArrays with a collection of digital signals.
112// Every signal from one array is compared with any from the other array.
113// For all signals which overlap and which have an overlap time >gate
114// a new digital signal is created storing start time and length of overlap.
115// They are collected in a newly allocated TObjArray. A pointer to this array
116// is returned.
117//
118// The user gains owenership of the object, i.e., the user is responsible of
119// deleting the memory.
120//
121TObjArray *MSimTrigger::CalcCoincidence(const TObjArray &arr1, const TObjArray &arr2/*, Float_t gate*/) const
122{
123 TObjArray *res = new TObjArray;
124
125 if (arr1.GetEntriesFast()==0 || arr2.GetEntriesFast()==0)
126 return res;
127
128 TIter Next1(&arr1);
129 MDigitalSignal *ttl1 = 0;
130 while ((ttl1=static_cast<MDigitalSignal*>(Next1())))
131 {
132 TIter Next2(&arr2);
133 MDigitalSignal *ttl2 = 0;
134 while ((ttl2=static_cast<MDigitalSignal*>(Next2())))
135 {
136 MDigitalSignal *ttl = new MDigitalSignal(*ttl1, *ttl2);
137 /*
138 if (ttl->GetLength()<=gate)
139 {
140 delete ttl;
141 continue;
142 }
143 */
144 res->Add(ttl);
145 }
146 }
147
148 res->SetOwner();
149
150 return res;
151}
152
153class Edge : public TObject
154{
155private:
156 Double_t fEdge;
157 Int_t fRising;
158
159public:
160 Edge(Double_t t, Int_t rising) : fEdge(t), fRising(rising) { }
161 Bool_t IsSortable() const { return kTRUE; }
162 Int_t Compare(const TObject *o) const { const Edge *e = static_cast<const Edge*>(o); if (e->fEdge<fEdge) return 1; if (e->fEdge>fEdge) return -1; return 0; }
163
164 Int_t IsRising() const { return fRising; }
165 Double_t GetEdge() const { return fEdge; }
166};
167
168// --------------------------------------------------------------------------
169//
170// Calculate a multiplicity trigger on the given array(s). The idx-array
171// conatins all channels which should be checked for coincidences
172// and the ttls array conatins the arrays with the digital signals.
173//
174// For the windows in which more or euqal than threshold channels have
175// a high signal a new MDigitalSignal is created. newly allocated
176// array with a collection of these trigger signals is returned.
177//
178TObjArray *MSimTrigger::CalcMinMultiplicity(const MArrayI &idx, const TObjArray &ttls, Int_t threshold) const
179{
180 // Create a new array for the rising and falling edges of the signals
181 TObjArray times;
182 times.SetOwner();
183
184 // Fill the array with edges from all digital signals of all our channels
185 for (UInt_t k=0; k<idx.GetSize(); k++)
186 {
187 TObjArray *arr = static_cast<TObjArray*>(ttls[idx[k]]);
188
189 TIter Next(arr);
190 MDigitalSignal *ttl = 0;
191 while ((ttl=static_cast<MDigitalSignal*>(Next())))
192 {
193 times.Add(new Edge(ttl->GetStart(), 1));
194 times.Add(new Edge(ttl->GetEnd(), -1));
195 }
196 }
197
198 // Sort them in time
199 times.Sort();
200
201 // Start with no channel active
202 Int_t lvl = 0;
203
204 TObjArray *res = new TObjArray;
205 res->SetOwner();
206
207 // First remove all edges which do not change the status
208 // "below threshold" or "above threshold"
209 for (int i=0; i<times.GetEntriesFast(); i++)
210 {
211 // Get i-th edge
212 const Edge &e = *static_cast<Edge*>(times.UncheckedAt(i));
213
214 // Claculate what the number of active channels after the edge is
215 const Int_t lvl1 = lvl + e.IsRising();
216
217 // Remove edge if number of active channels before and after the
218 // edge lower is lower than the threshold or higher than
219 // the threshold
220 if (lvl+1<threshold || lvl-1>=threshold)
221 delete times.RemoveAt(i);
222
223 // keep the (now) "previous" level
224 lvl = lvl1<0 ? 0 : lvl1;
225 }
226
227 // Remove the empty slots from the array
228 times.Compress();
229
230 //
231 for (int i=0; i<times.GetEntriesFast()-1; i++)
232 {
233 // get the current edge
234 const Edge &e0 = *static_cast<Edge*>(times.UncheckedAt(i));
235
236 // go ahead if this is a falling edge
237 if (e0.IsRising()!=1)
238 continue;
239
240 // get the following edge (must be a falling edge now)
241 const Edge &e1 = *static_cast<Edge*>(times.UncheckedAt(i+1));
242
243 // calculate the length of the digital signal
244 const Double_t len = e1.GetEdge()-e0.GetEdge();
245
246 // Create a digital trigger signal
247 MDigitalSignal *ds = new MDigitalSignal(e0.GetEdge(), len);
248 //ds->SetIndex(lvl);
249 res->Add(ds);
250 }
251
252 return res;
253}
254
255// --------------------------------------------------------------------------
256//
257// Check for the necessary parameter containers. Read the luts.
258//
259Int_t MSimTrigger::PreProcess(MParList *pList)
260{
261 fTrigger = (MParameterD*)pList->FindCreateObj("MParameterD", "TriggerPos");
262 if (!fTrigger)
263 return kFALSE;
264
265 fPulsePos = (MParameterD*)pList->FindObject("IntendedPulsePos", "MParameterD");
266 if (!fPulsePos)
267 {
268 *fLog << err << "IntendedPulsePos [MParameterD] not found... aborting." << endl;
269 return kFALSE;
270 }
271
272 fCamera = (MAnalogChannels*)pList->FindObject("MAnalogChannels");
273 if (!fCamera)
274 {
275 *fLog << err << "MAnalogChannels not found... aborting." << endl;
276 return kFALSE;
277 }
278
279 fElectronicNoise = 0;
280 if (fShiftBaseline)
281 {
282 fElectronicNoise = (MPedestalCam*)pList->FindObject("ElectronicNoise", "MPedestalCam");
283 if (!fElectronicNoise)
284 {
285 *fLog << err << "ElectronicNoise [MPedestalCam] not found... aborting." << endl;
286 return kFALSE;
287 }
288 *fLog << inf << "Baseline will be shifted back to 0 for discriminator." << endl;
289 }
290
291 fGain = 0;
292 if (fUngainSignal)
293 {
294 fGain = (MPedestalCam*)pList->FindObject("Gain", "MPedestalCam");
295 if (!fGain)
296 {
297 *fLog << err << "Gain [MPedestalCam] not found... aborting." << endl;
298 return kFALSE;
299 }
300 *fLog << inf << "Discriminator will be multiplied by applied gain." << endl;
301 }
302
303 fRunHeader = (MRawRunHeader*)pList->FindObject("MRawRunHeader");
304 if (!fRunHeader)
305 {
306 *fLog << err << "MRawRunHeader not found... aborting." << endl;
307 return kFALSE;
308 }
309
310 fEvtHeader = (MRawEvtHeader*)pList->FindCreateObj("MRawEvtHeader");
311 if (!fEvtHeader)
312 return kFALSE;
313
314 fRouteAC.Delete();
315 if (!fNameRouteAC.IsNull() && fRouteAC.ReadFile(fNameRouteAC)<0)
316 return kFALSE;
317
318 fCoincidenceMap.Delete();
319 if (!fNameCoincidenceMap.IsNull() && fCoincidenceMap.ReadFile(fNameCoincidenceMap)<0)
320 return kFALSE;
321
322 // ---------------- Consistency checks ----------------------
323
324 if (!fRouteAC.IsEmpty() && !fCoincidenceMap.IsEmpty() &&
325 fCoincidenceMap.GetMaxIndex()>fRouteAC.GetNumRows()-1)
326 {
327 *fLog << err;
328 *fLog << "ERROR - AC routing produces " << fRouteAC.GetNumRows() << " analog channels," << endl;
329 *fLog << " but the coincidence map expects at least " << fCoincidenceMap.GetMaxIndex()+1 << " channels." << endl;
330 return kERROR;
331 }
332
333 if (fDiscriminatorThreshold<=0)
334 {
335 *fLog << err << "ERROR - Discriminator threshold " << fDiscriminatorThreshold << " invalid." << endl;
336 return kFALSE;
337 }
338
339 if (fElectronicNoise && !fRouteAC.IsEmpty() && !fRouteAC.IsDefaultCol())
340 {
341 // FIXME: Apply to analog channels when summing
342 *fLog << warn << "WARNING - A baseline shift doesn't make sense for sum-channels... reset." << endl;
343 fElectronicNoise = 0;
344 }
345
346 if (fGain && !fRouteAC.IsEmpty() && !fRouteAC.IsDefaultCol())
347 {
348 // FIXME: Apply to analog channels when summing
349 *fLog << warn << "WARNING - Ungain doesn't make sense for sum-channels... reset." << endl;
350 fGain = 0;
351 }
352
353
354 // ---------------- Information output ----------------------
355
356 *fLog << inf;
357
358 if (fRouteAC.IsEmpty())
359 *fLog << "Re-routing/summing of analog channels before discriminator switched off." << endl;
360 else
361 *fLog << "Using " << fNameRouteAC << " for re-routing/summing of analog channels before discriminator." << endl;
362
363 if (fCoincidenceMap.IsEmpty() && fMinMultiplicity==0)
364 *fLog << "No coincidences of digital channels will be checked. Signal-above-threshold trigger applied." << endl;
365 else
366 {
367 *fLog << "Using ";
368 if (fCoincidenceMap.IsEmpty())
369 *fLog << "the whole camera";
370 else
371 *fLog << "patterns from " << fNameCoincidenceMap;
372 *fLog << " to check for ";
373 if (fMinMultiplicity==0)
374 *fLog << "coincidences of the digital channels." << endl;
375 else
376 *fLog << fMinMultiplicity << " multiplicity." << endl;
377 }
378
379 *fLog << "Using discriminator threshold of " << fDiscriminatorThreshold << endl;
380
381 return kTRUE;
382}
383
384/*
385class MDigitalChannel : public TObjArray
386{
387private:
388 TObjArray fArray;
389
390public:
391 MDigitalSignal *GetSignal(UInt_t i) { return static_cast<MDigitalSignal*>(fArray[i]); }
392
393};
394*/
395
396#include "MCamEvent.h"
397class MTriggerSignal : public MParContainer, public MCamEvent
398{
399private:
400 TObjArray fSignals;
401
402public:
403 MTriggerSignal() { fSignals.SetOwner(); }
404
405 void Add(MDigitalSignal *signal) { fSignals.Add(signal); }
406
407 MDigitalSignal *GetSignal(UInt_t i) { return static_cast<MDigitalSignal*>(fSignals[i]); }
408
409 void Sort() { fSignals.Sort(); }
410
411 Int_t GetNumSignals() const { return fSignals.GetEntriesFast(); }
412
413 Float_t GetFirstTrigger() const
414 {
415 MDigitalSignal *sig = static_cast<MDigitalSignal*>(fSignals[0]);
416 return sig ? sig->GetStart() : -1;
417 }
418 Bool_t GetPixelContent(Double_t&, Int_t, const MGeomCam&, Int_t) const
419 {
420 switch (1)
421 {
422 case 1: // yes/no
423 case 2: // first time
424 case 3: // length
425 case 4: // n
426 break;
427 }
428
429 return kTRUE;
430 }
431 void DrawPixelContent(Int_t) const
432 {
433 }
434};
435
436
437void MSimTrigger::SetTrigger(Double_t pos)
438{
439 // FIXME: Jitter! (Own class?)
440 fTrigger->SetVal(pos);
441 fTrigger->SetReadyToSave();
442
443 // Trigger pattern to be set
444 // FIXME: Make flexible
445 const UInt_t pat = (UInt_t)~(MTriggerPattern::kTriggerLvl1 | (MTriggerPattern::kTriggerLvl1<<8));
446
447 // Flag this event as triggered by the lvl1 trigger (FIXME?)
448 fEvtHeader->SetTriggerPattern(pos<0 ? 0 : pat);
449 fEvtHeader->SetReadyToSave();
450}
451
452// --------------------------------------------------------------------------
453//
454Int_t MSimTrigger::Process()
455{
456 // Invalidate trigger
457 //fTrigger->SetVal(-1);
458 // Calculate the minimum and maximum time for a valid trigger
459 const Double_t freq = fRunHeader->GetFreqSampling()/1000.;
460 const Float_t nsamp = fRunHeader->GetNumSamplesHiGain();
461 const Float_t pulspos = fPulsePos->GetVal()/freq;
462
463 // Valid range in units of bins
464 const Float_t min = fCamera->GetValidRangeMin()+pulspos;
465 const Float_t max = fCamera->GetValidRangeMax()-(nsamp-pulspos);
466
467 if (!fSimulateElectronics)
468 {
469 SetTrigger(min);
470 return kTRUE;
471 }
472
473 // ================== Simulate channel bundling ====================
474
475 // FIXME: Before we can bundle the channels we have to make a copy
476 // and simulate clipping
477
478 // Check if routing should be done
479 const Bool_t empty = fRouteAC.IsEmpty();
480
481 // If no channels are summed the number of patches stays the same
482 const UInt_t npatch = empty ? fCamera->GetNumChannels() : fRouteAC.GetEntriesFast();
483
484 // Use the given analog channels as default out. If channels are
485 // summed overwrite with a newly allocated set of analog channels
486 MAnalogChannels *patches = fCamera;
487 if (!empty)
488 {
489 // FIXME: Can we add gain and offset here into a new container?
490
491 patches = new MAnalogChannels(npatch, fCamera->GetNumSamples());
492 for (UInt_t i=0; i<npatch; i++)
493 {
494 const MArrayI &row = fRouteAC.GetRow(i);
495 for (UInt_t j=0; j<row.GetSize(); j++)
496 {
497 const UInt_t idx = row[j];
498
499 // FIXME: Shrinking the mapping table earlier (e.g.
500 // ReInit) would avoid a lot of if's
501 if (idx<fCamera->GetNumChannels())
502 (*patches)[i].AddSignal((*fCamera)[idx]);
503 }
504 }
505 }
506
507 // FIXME: Write patches
508
509 // ================== Simulate discriminators ====================
510
511 TObjArray ttls(npatch);
512 ttls.SetOwner();
513
514 for (UInt_t i=0; i<npatch; i++)
515 {
516 // FIXME: What if the gain was also allpied to the baseline?
517 const Double_t offset = fElectronicNoise ? (*fElectronicNoise)[i].GetPedestal() : 0;
518 const Double_t gain = fGain ? (*fGain)[i].GetPedestal() : 1;
519 ttls.AddAt((*patches)[i].Discriminate(fDiscriminatorThreshold*gain+offset, fDigitalSignalLength), i);
520 }
521
522 // FIXME: Write TTLs!
523
524 // If analog channels had been newly allocated free memmory
525 if (patches!=fCamera)
526 delete patches;
527
528 // =================== Simulate coincidences ======================
529
530 // If the map is empty we create a one-pixel-coincidence map
531 // FIMXE: This could maybe be accelerated if the Clone can be
532 // omitted in the loop
533 if (fCoincidenceMap.IsEmpty())
534 {
535 if (fMinMultiplicity>0)
536 fCoincidenceMap.SetDefaultRow(npatch);
537 else
538 fCoincidenceMap.SetDefaultCol(npatch);
539 }
540
541 // Create an array for the individual triggers
542 MTriggerSignal triggers;
543
544 Int_t cnt = 0;
545 Int_t rmlo = 0;
546 Int_t rmhi = 0;
547
548 for (int j=0; j<fCoincidenceMap.GetEntries(); j++)
549 {
550 const MArrayI &idx = fCoincidenceMap.GetRow(j);
551
552 TObjArray *arr = 0;
553
554 if (fMinMultiplicity>0)
555 {
556 arr = CalcMinMultiplicity(idx, ttls, fMinMultiplicity);
557 }
558 else
559 {
560 arr = CalcMinMultiplicity(idx, ttls, idx.GetSize());
561 /*
562 // Start with a copy of the first coincidence channel
563 arr = static_cast<TObjArray*>(ttls[idx[0]]->Clone());
564 arr->SetOwner();
565
566 // compare to all other channels in this coincidence patch, one by one
567 for (UInt_t k=1; k<idx.GetSize() && arr->GetEntriesFast()>0; k++)
568 {
569 TObjArray *res = CalcCoincidence(*arr, *static_cast<TObjArray*>(ttls[idx[k]]));//, fCoincidenceTime);
570
571 // Delete the original array and keep the new one
572 delete arr;
573 arr = res;
574 }*/
575 }
576
577 // Count the number of totally emitted coincidence signals
578 cnt += arr->GetEntriesFast();
579
580 // Remove all signals which are not in the valid digitization range
581 // (This is not the digitization window, but the region in which
582 // the analog channels contain usefull data)
583 // and which are shorter than the defined coincidence gate.
584 TIter Next(arr);
585 MDigitalSignal *ttl = 0;
586 while ((ttl=static_cast<MDigitalSignal*>(Next())))
587 {
588 if (ttl->GetLength()<fCoincidenceTime)
589 {
590 delete arr->Remove(ttl);
591 continue;
592 }
593
594 if (ttl->GetStart()<min)
595 {
596 delete arr->Remove(ttl);
597 rmlo++;
598 continue;
599 }
600 if (ttl->GetStart()>max)
601 {
602 delete arr->Remove(ttl);
603 rmhi++;
604 continue;
605 }
606
607 // Set trigger channel index
608 ttl->SetIndex(j);
609 }
610
611 // Remove the empty slots
612 arr->Compress();
613
614 // If we have at least one trigger keep the earliest one.
615 // FIXME: The triggers might be ordered in time automatically:
616 // To be checked!
617 // FIXME: Simulate trigger dead-time!
618 if (arr->GetEntriesFast()>0)
619 triggers.Add(static_cast<MDigitalSignal*>(arr->RemoveAt(0)));
620
621 // delete the allocated space
622 delete arr;
623 }
624
625 // There are usually not enough entries that it is worth to search
626 // for the earliest instead of just sorting and taking the first one
627 // FIXME: This could be improved if checking for IsSortable
628 // is omitted
629 triggers.Sort();
630 // FIXME: Store triggers! (+ Reversed pixels?)
631
632 SetTrigger(triggers.GetFirstTrigger());
633
634 // No trigger issued. Go on.
635 if (triggers.GetNumSignals()==0)
636 {
637 if (rmlo>0 || rmhi>0)
638 *fLog << inf2 << GetNumExecutions() << ": " << rmlo << "/" << rmhi << " trigger out of valid range. No trigger raised." << endl;
639 return kTRUE;
640 }
641
642 // Number of patches which have triggered out of the total number of
643 // Coincidence signals emitted. (If the total number is higher than
644 // the number of triggers either some triggers had to be removed or
645 // or a patch has emitted more than one trigger signal)
646 // FIXME: inf2?
647 *fLog << inf << GetNumExecutions() << ": ";
648 *fLog << setw(3) << triggers.GetNumSignals() << " triggers left out of ";
649 *fLog << setw(3) << cnt << " (" << rmlo << "/" << rmhi << " trigger out of valid range), T=" << fTrigger->GetVal();
650 *fLog << endl;
651
652 //# Trigger characteristics: gate length (ns), min. overlapping time (ns),
653 //# amplitude and FWHM of (gaussian) single phe response for trigger:
654 //trigger_prop 3.0 0.25 1.0 2.0
655
656 return kTRUE;
657}
658
659// --------------------------------------------------------------------------
660//
661// FileNameRouteac: routeac.txt
662// FileNameCoincidenceMap: coincidence.txt
663// DiscriminatorTheshold: 3.5
664// DigitalSignalLength: 8
665// CoincidenceTime: 0.5
666// SimulateElectronics: Yes
667//
668Int_t MSimTrigger::ReadEnv(const TEnv &env, TString prefix, Bool_t print)
669{
670 Bool_t rc = kFALSE;
671 if (IsEnvDefined(env, prefix, "FileNameRouteAC", print))
672 {
673 rc = kTRUE;
674 fNameRouteAC = GetEnvValue(env, prefix, "FileNameRouteAC", fNameRouteAC);
675 }
676
677 if (IsEnvDefined(env, prefix, "FileNameCoincidenceMap", print))
678 {
679 rc = kTRUE;
680 fNameCoincidenceMap = GetEnvValue(env, prefix, "FileNameCoincidenceMap", fNameCoincidenceMap);
681 }
682
683 if (IsEnvDefined(env, prefix, "DiscriminatorThreshold", print))
684 {
685 rc = kTRUE;
686 fDiscriminatorThreshold = GetEnvValue(env, prefix, "DiscriminatorThreshold", fDiscriminatorThreshold);
687 }
688
689 if (IsEnvDefined(env, prefix, "DigitalSignalLength", print))
690 {
691 rc = kTRUE;
692 fDigitalSignalLength = GetEnvValue(env, prefix, "DigitalSignalLength", fDigitalSignalLength);
693 }
694
695 if (IsEnvDefined(env, prefix, "CoincidenceTime", print))
696 {
697 rc = kTRUE;
698 fCoincidenceTime = GetEnvValue(env, prefix, "CoincidenceTime", fCoincidenceTime);
699 }
700
701 if (IsEnvDefined(env, prefix, "SimulateElectronics", print))
702 {
703 rc = kTRUE;
704 fSimulateElectronics = GetEnvValue(env, prefix, "SimulateElectronics", fSimulateElectronics);
705 }
706
707 if (IsEnvDefined(env, prefix, "MinMultiplicity", print))
708 {
709 rc = kTRUE;
710 fMinMultiplicity = GetEnvValue(env, prefix, "MinMultiplicity", fMinMultiplicity);
711 }
712
713 return rc;
714}
Note: See TracBrowser for help on using the repository browser.