ATLAS Offline Software
Loading...
Searching...
No Matches
CscCalcSlope.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
5#include "CscCalcSlope.h"
6
10#include "GaudiKernel/Chrono.h"
14
15#include "TF1.h"
16#include "TGraphErrors.h"
17#include "TFile.h"
18#include "TProfile.h"
19
20#include <iostream>
21#include <fstream>
22#include <bitset>
23#include <inttypes.h>
24
25namespace MuonCalib {
26
27 CscCalcSlope::CscCalcSlope(const std::string& name, ISvcLocator* pSvcLocator) :
28 AthAlgorithm(name,pSvcLocator),
29 m_outputFileName("output.cal"),
30 m_dumpAllHists(false),
33 m_fracProfs(nullptr),
34 m_fracGraphs(nullptr),
35 m_resGraph(nullptr),
36 m_currentAmpProf(nullptr),
37 m_eventCnt(0),
38 m_slopes(nullptr),
39 m_intercepts(nullptr),
40 m_peds(nullptr),
41 m_noises(nullptr),
42 m_peakTimeProf(nullptr),
43 m_peakTimes(nullptr),
44 m_numBits(12)
45 {
46 declareProperty("OutputFile", m_outputFileName = "");
47 declareProperty("IgnoreDatabaseError",m_ignoreDatabaseError = false); //Set to true to ignore database errors
48 declareProperty("TitlePrefix",m_titlePrefix = ""); //Prefix appended to title of histograms and graphs
49 declareProperty("TitlePostfix",m_titlePostfix = ""); //Postfix appended to title of histograms and graphs
50
51 //test parameters
52 declareProperty("DoBipolarFit", m_doBipolarFit = true);
53 declareProperty("DoCrossTalkFix",m_doCrossTalkFix = true);
54
55 declareProperty("GetPedFromFile",m_pedFile = false);
56 declareProperty("PedFileName",m_pedFileName = "");
57
58 declareProperty("ExpectedChamberLayer", m_expectedChamberLayer = 2);
59
60 declareProperty("DoLinPlot" , m_doLinPlot = false);
61 declareProperty("CalibFitFunction" , m_calFitFunc = "[0] + [1]*10^(x/-20)");
62 declareProperty("MinDeltaAdc",m_minDeltaAdc = 10, "Minimum change in ADC a calgraph needs to drop for a fit lower bound to be set");
63
64 /*
65 ADC = mC(db) = m*C_max*10^(db/20) + intercept // C_max = maximum charge
66
67 we divide by c_max later to get m (the function as in m_calFitFunc has
68 [1] = max ADC, so we divide max charge to get
69
70 since attenuation is negative
71
72 db = -20 log(ADC+intercept/mC_max)
73
74 db = -20 log(ADC - intercept / mC_max)
75
76 (-20 since V^2 gives power disipation)
77
78 */
79
80 declareProperty("FindPeakTime", m_findPeakTime = true);
81 declareProperty("DoBitHists", m_doBitHists = true);
82
83 declareProperty("CalOutputVersion", m_calOutputVersion="03-00");
84
85 m_crossTalkFix[0] = 1.0322840930;
86 m_crossTalkFix[1] = 1.0422690324;
87 m_crossTalkFix[2] = 1.0235384586;
88 m_crossTalkFix[3] = 1.0183445962;
89 m_crossTalkFix[4] = 1.0151409212;
90 m_crossTalkFix[5] = 1.0152511102;
91 m_crossTalkFix[6] = 1.0103618910;
92 m_crossTalkFix[7] = 1.0113985580;
93 m_crossTalkFix[8] = 1.0040464232;
94 m_crossTalkFix[9] = 1.0049431193;
95 m_crossTalkFix[10] = 0.9997829589;
96 m_crossTalkFix[11] = 1.0003994005;
97 m_crossTalkFix[12] = 0.9826108255;
98 m_crossTalkFix[13] = 0.9850002836;
99 m_crossTalkFix[14] = 0.9831852065;
100 m_crossTalkFix[15] = 0.9826508145;
101 m_crossTalkFix[16] = 0.9804885017;
102 m_crossTalkFix[17] = 0.9811262196;
103 m_crossTalkFix[18] = 0.9784119832;
104 m_crossTalkFix[19] = 0.9777689757;
105 m_crossTalkFix[20] = 0.9704773978;
106 m_crossTalkFix[21] = 0.9738781078;
107 m_crossTalkFix[22] = 0.9710430303;
108 m_crossTalkFix[23] = 0.9743144079;
109 }
110
112 {
113 ATH_MSG_INFO("CscCalcSlope::initialize() called");
114
115 //*******Register services and tools *********/
116 ATH_CHECK(m_idHelperSvc.retrieve());
117
118 m_chronoSvc = service("ChronoStatSvc");
119 ATH_CHECK(m_chronoSvc.isValid());
120
121 ATH_CHECK(m_cscCalibTool.retrieve());
122
123 ATH_CHECK(m_cscRdoDecoderTool.retrieve());
124
125 ATH_MSG_INFO("Finished initializing services. ");
126 //*****Initialize internal variables and histograms*******/
127 m_ampProfs.clear();
128 //Setup lookup table for pulser levels
129 m_dbLevels.resize(64);
130 for(unsigned int pulserLevel=0; pulserLevel < 64; pulserLevel++)
131 m_dbLevels[pulserLevel] = pulserLevel*.5;
132
133 IdContext channelContext = m_idHelperSvc->cscIdHelper().channel_context();
134
135 if(m_doBitHists) m_bitHists.clear();
136 //Loop through ids to find out what hash range we're working on, and to
137 //initialize histograms.
138 const std::vector<Identifier> & ids = m_idHelperSvc->cscIdHelper().idVector();
139
140
141 m_maxStripHash = 0;
142 for(const auto & thisChamberId:ids)
143 {
144 std::vector<Identifier> stripVect;
145 m_idHelperSvc->cscIdHelper().idChannels(thisChamberId,stripVect);
146
147
148
149 for(const auto & thisStripId:stripVect)
150 {
151 IdentifierHash stripHash;
152 m_idHelperSvc->cscIdHelper().get_channel_hash(thisStripId,stripHash);
153
154 if(m_maxStripHash < (unsigned int)stripHash)
155 m_maxStripHash = (unsigned int)stripHash;
156
157 if(m_doBitHists)
158 {
159 Identifier id;
160 m_idHelperSvc->cscIdHelper().get_id((IdentifierHash)stripHash,id,&channelContext);
161 int wireLayer = m_idHelperSvc->cscIdHelper().wireLayer(id);
162 char orientation = (m_idHelperSvc->cscIdHelper().measuresPhi(id) ? 'Y':'X');
163
164 int stationName = m_idHelperSvc->cscIdHelper().stationName(id);
165 int stationPhi = m_idHelperSvc->cscIdHelper().stationPhi(id);
166 int stationEta = m_idHelperSvc->cscIdHelper().stationEta(id);
167
168 int stripNumber = m_idHelperSvc->cscIdHelper().strip(id);
169
170 char bitName[200], titleSeed[500];
171 //Bit histogram (for looking for stuck-bits)
172 sprintf(bitName, "bitHist%d",(int)stripHash);
173 sprintf(titleSeed, "Bit histogram for eta %d, sector %d, layer %d%c strip %d",
174 stationEta,(2*stationPhi+50 - stationName),wireLayer,orientation,stripNumber);
175 std::string title = m_titlePrefix + titleSeed + m_titlePostfix;
176 TH1I* hist = new TH1I(bitName, title.c_str(), m_numBits, 0, m_numBits); //12 bits
177 hist->GetXaxis()->SetTitle("Bit");
178 hist->GetYaxis()->SetTitle("Counts");
179 m_bitHists.push_back(hist);
180 }
181 }
182 }//end chamber loop
183
184 m_fitReturns.clear();
185 m_fitReturns.resize(m_maxStripHash+1,0);
186
187 m_calGraphs.clear();
188 for(unsigned int chanItr =0; chanItr <= m_maxStripHash; chanItr++)
189 {
190 m_calGraphs.push_back(nullptr);
191 }
192
193
194 if(m_pedFile)
195 {
196 ATH_MSG_INFO("Opening pedestal file");
197 std::ifstream in(m_pedFileName.c_str());
198 int stripHash;
199 double ped,noise;//,pedError,noiseError;
200 std::string buff;
201 in >> buff >> buff >> buff >> buff >> buff ;// skip header
202 m_peds = new float[m_maxStripHash+1];
203 m_noises = new float[m_maxStripHash+1];
204
205 while(!in.eof())
206 {
207 in >> stripHash >> buff >> buff >> ped >> noise;
208 ATH_MSG_INFO(stripHash << "\t" << ped << "\t" << noise);
209 if( stripHash < 0 || (unsigned int) stripHash > m_maxStripHash ) {
210 //cppcheck-suppress shiftNegative
211 ATH_MSG_FATAL("The hash "<< (int) stripHash << " is out of range for the Ped-Vector - Crashing!");
212 return StatusCode::FAILURE;
213 }
214 m_peds[stripHash] = ped;
215 m_noises[stripHash] = noise;
216 }
217 }
218 else
219 {
220 ATH_CHECK(m_readKey.initialize());
221 }
222
223 ATH_MSG_INFO("Counted " << m_maxStripHash +1 << " strips.");
224
225 m_slopes = new CscCalibResultCollection("pslope");
227
229 {
230 m_peakTimeProf = new TProfile("PeakTimes","Peaking Time for each channel",m_maxStripHash+1,
231 0,m_maxStripHash+1);
233 }
234
235 m_pulsedChambers.clear();
236
237
238 ATH_MSG_DEBUG("End initialize");
239 return StatusCode::SUCCESS;
240 }//end initialize
241
242 //Execute loops through all strips and fills histograms
244 {
245 ATH_MSG_INFO("Begin execute");
246 //collectEventInfo collects infomation about each event by filling ampHistCollection and peaktHist.
247 StatusCode sc = collectEventInfo();
248
249 if(!sc.isSuccess())
250 {
251 ATH_MSG_WARNING("There was an error collecting information from the RDO this event.");
252 return sc;
253 }
254 ATH_MSG_INFO("End execute");
255 return StatusCode::SUCCESS;
256 } //end execute()
257
259 {
260 ATH_MSG_INFO("In finalize()");
261
262 StatusCode sc;
263
264 bool thereIsAFatal=false;
265
266 //calculateParameters() finds means and fits gain curves from the data in
269 if(sc.isFailure())
270 {
271 ATH_MSG_WARNING("Calculation of parameters failed!");
272 }
273 ATH_MSG_DEBUG("Finished calculating parameters");
274
275 //writeCalibrationFile() writes the calculated parameters into a calibration fie.
277 if(!sc.isSuccess())
278 {
279 ATH_MSG_FATAL("Failed to write parameters to disk!");
280 thereIsAFatal = true; //Not quiting yet to ensure memory is properly deleted
281 }
282
284 if(sc.isFailure())
285 {
286 ATH_MSG_FATAL("Failed to record parameters in StoreGate ");
287 thereIsAFatal = true;
288 }
289
290 delete m_peakTimeProf;
291
292 ATH_MSG_DEBUG("Finished finalize()");
293
294 if(thereIsAFatal)
295 return StatusCode::FAILURE;
296
297 return StatusCode::SUCCESS;
298 }//end finalize()
299
300
301 //Collect event info is run every event, gathering amplitutdes and peakting times.
303 {
304 MsgStream mLog( msgSvc(), name() );
305
306 // apparently not used since code is exited automatically if there is an error
307 // bool thereIsAnError = false;
308
309 Chrono chrono(m_chronoSvc,"collectEventInfo");
310 ATH_MSG_DEBUG("Collecting event info for event " << m_eventCnt);
311 //Below might need to be changed depending on how we get data
312 const CscRawDataContainer* fullRDO;
313 StatusCode sc_read = evtStore()->retrieve(fullRDO, "CSCRDO");
314 if (sc_read != StatusCode::SUCCESS)
315 {
316 ATH_MSG_FATAL("Could not find event");
317 return StatusCode::FAILURE;
318 }
319
321 const CscCondDbData* readCdo{*readHandle};
322
323 //Loop over RODs (data from 2 chambers), each of which is in
324 //a single CscRawaData collection
325
326
327 for(const auto rod:*fullRDO)
328 {
329 if(not rod->empty())
330 {
331
332 uint16_t pulsedWireLayer = rod->calLayer();
333
334 int pulserLevel = rod->calAmplitude();
335 ATH_MSG_VERBOSE("Pulser level is " << pulserLevel);
336 if( pulserLevel != m_lastPulserLevel)
337 {
338 ATH_MSG_INFO("New pulser level found. (" << pulserLevel <<").");
339
340 std::map<int,TProfile*>::iterator alreadyExistingProfile = m_ampProfs.find(pulserLevel);
341
342 if(alreadyExistingProfile == m_ampProfs.end())
343 {//No previous profile for this amplitude exists
344
345 ATH_MSG_DEBUG(" creating new amplitude profile");
346 std::stringstream name, title;
347 name << "ampProf_" << pulserLevel;
348 title << m_titlePrefix << "Amplitudes For Pulser Level " << pulserLevel << m_titlePostfix;
349 m_currentAmpProf = new TProfile(name.str().c_str(), title.str().c_str(),
351 m_currentAmpProf->GetXaxis()->SetTitle("Channel (Hash Id)");
352 m_currentAmpProf->GetYaxis()->SetTitle("Amplitude (ADC value)");
353 ATH_MSG_DEBUG("Adding new amplitude profile");
354 m_ampProfs.insert(std::pair<int, TProfile*>( pulserLevel, m_currentAmpProf));
355 }
356 else
357 {
358 ATH_MSG_DEBUG(" using existing amplitude profile");
359 m_currentAmpProf = alreadyExistingProfile->second;
360 }
361
362 m_lastPulserLevel = pulserLevel;
363 }
364
365 unsigned int samplingPhase = rod->samplingPhase();
366 uint8_t samplingPeriod = rod->rate(); //sampling period in ns
367
368
369 //Loop over strips in rod
370
371
372 for(const auto cluster: *rod)
373 {
374 //Note: For a pulser or ped run, the "cluster"
375 //is the size of an entire layer
376 int numStrips = cluster->width();
377 int samplesPerStrip = (cluster->samples()).size()/numStrips;
378
379 IdContext channelContext = m_idHelperSvc->cscIdHelper().channel_context();
380
381 for(int stripItr = 0; stripItr <numStrips; stripItr++)
382 {
383 Identifier stripId =m_cscRdoDecoderTool->channelIdentifier(cluster, &m_idHelperSvc->cscIdHelper(), stripItr);
384 IdentifierHash cscChannelHashId;
385 m_idHelperSvc->cscIdHelper().get_channel_hash(stripId, cscChannelHashId);
386 int stripHash = cscChannelHashId;
387 ATH_MSG_VERBOSE("The eta of this strip is: " << m_idHelperSvc->cscIdHelper().stationEta(stripId));
388
389 int chamberLayer = m_idHelperSvc->cscIdHelper().chamberLayer(stripId);
390 if(chamberLayer != m_expectedChamberLayer)
391 {
392 ATH_MSG_FATAL("Cluster includes strip in chamber layer "
393 << chamberLayer << ". Only " << m_expectedChamberLayer
394 << " is valid.");
395 return StatusCode::FAILURE;
396 }
397
398 int currentWireLayer = m_idHelperSvc->cscIdHelper().wireLayer(stripId) - 1;
399 if( currentWireLayer < 0 || currentWireLayer > 3)
400 {
401 ATH_MSG_FATAL("Problem in getting wire layer! - Current value is "
402 << m_idHelperSvc->cscIdHelper().wireLayer(stripId) << " while only values between 1-4 are allowed.");
403 return StatusCode::FAILURE;
404 }
405 bool isThisLayerPulsed = (pulsedWireLayer >> currentWireLayer)&0x1;
406 if(isThisLayerPulsed)
407 {
408
409 std::vector<uint16_t> samples;
410 cluster->samples(stripItr,samplesPerStrip,samples); //Retrieve samples for a single strip
411
412 float ped = 0;
413 float noise = 0;
414 if(m_pedFile)
415 {
416 ped = m_peds[stripHash];
417 noise = m_noises[stripHash];
418 }
419 else{
420
421 if(!readCdo->readChannelPed(stripHash, ped).isSuccess()){
422 ped = 2054;
423 if (m_ignoreDatabaseError) ATH_MSG_WARNING("Failed at getting pedestal from COOL for hash " << stripHash);
424 else ATH_MSG_ERROR("Failed at getting pedestal from COOL for hash " << stripHash);
426 return StatusCode::RECOVERABLE;
427 ATH_MSG_WARNING("Setting to " << ped);
428 }
429 else
430 ATH_MSG_VERBOSE("Got pedestal of " << ped);
431 if(!readCdo->readChannelNoise(stripHash, noise).isSuccess())
432 {
433 noise = .001;
434 if (m_ignoreDatabaseError) ATH_MSG_WARNING("Failed at getting noise from COOL for hash " << stripHash);
435 else ATH_MSG_ERROR("Failed at getting noise from COOL for hash " << stripHash);
437 return StatusCode::FAILURE;
438 ATH_MSG_WARNING("Setting to " << noise);
439 }
440
441 }
442
443 double peakAmp{}, peakTime{};
444 int success{};
445 if(!m_doBipolarFit)
446 {
447 //Need to convert vector from ints to floats to pass to findCharge
448 std::vector<float> floatSamples;
449 for(const auto & thisSample:samples){
450
451 floatSamples.push_back(thisSample-ped);
452 if(m_doBitHists){
453 if(!fillBitHist(m_bitHists[stripHash],thisSample)){
454 ATH_MSG_WARNING("Failed recording bits for strip " << stripHash);
455 }
456
457 }
458 }
459
460 success = m_cscCalibTool->findCharge((float)samplingPeriod, samplingPhase,floatSamples,peakAmp,peakTime);
461
462 }
463 else
464 {
465 //Need to convert vector from ints to doubles to pass to bipolar fit
466 double adcSamples[4];
467 for(int i = 0; i < 4; i++) adcSamples[i] = samples[i] -ped;
468 double fitResult[3],fitErrors[3], chi2;
469 double width = samplingPeriod == 50 ? 7.2:14.4; //check if 50 or 25ns period
470
471 m_bipolarFit.Fit(adcSamples,noise,ped,width,fitResult,fitErrors,&chi2);
472 success = true;
473 peakAmp = fitResult[0];
474 peakTime = fitResult[1] - (samplingPhase ? 25 : 0);
475 }//end if m_doBipolarFit
476
477
478 if(success)
479 {
480 m_currentAmpProf->Fill(stripHash,peakAmp);
481 //((*m_ampHists)[stripHash])->Fill(peakAmp);
482
484 m_peakTimeProf->Fill(stripHash,peakTime);
485 }
486 else
487 {
488 ATH_MSG_WARNING("Failed at fitting pulse shape. Debug info: ");
489 ATH_MSG_WARNING("stripHash " << stripHash);
490 ATH_MSG_WARNING("strip in chamber " << stripItr);
491 ATH_MSG_WARNING(" and detailed id " << m_idHelperSvc->cscIdHelper().show_to_string(stripId,&channelContext));
492 ATH_MSG_WARNING("Pulsed layer " << pulsedWireLayer<< ", Samples: " << samples[0] <<", " << samples[1] << ", " << samples[2] << ", " << samples[3]);
493 }
494 }//end if (islayerPulsedand and is precision layer)
495 }//end strip loop
496
497 }//end cluster loop
498 }//end if rod >1
499 }//end rod loop
500
501
502 ATH_MSG_DEBUG("end collectEventInfo()");
503 m_eventCnt++;
504
505 // at this part of the code thereIsAnError is always false - if true it would exit earlier
506 // if(thereIsAnError)
507 // return StatusCode::RECOVERABLE;
508
509 return StatusCode::SUCCESS;
510 }// end collectEventInfo()
511
512
513 //Calculate parameters is called during finalize, and calculates the parameter values from the
514 //data taken by collectEventData()
516 {
517 Chrono chrono(m_chronoSvc,"calculateParameters");
518 StatusCode sc;
519 ATH_MSG_INFO("Calculating calibration constants.");
520
521 unsigned int numCalibPoints = m_ampProfs.size();
522 ATH_MSG_INFO("There are " << numCalibPoints << " pulser levels to evaluate.");
523
524 IdContext channelContext = m_idHelperSvc->cscIdHelper().channel_context();
525
526 float chargeMax = 530.88; //in fC
527
528 int crossTalkCnt = 0;
529
530 for(unsigned int stripHash = 0 ;stripHash <= m_maxStripHash; stripHash++)
531 {
532
533 if(true)//stripHash < 50 || stripHash%1000 == 0)
534 {
535 ATH_MSG_INFO("Analyzing strip with hash " << stripHash << " out of " << m_maxStripHash);
536 }
537
538 //**Now tackle slope calculation
539
540
541 Identifier id;
542 m_idHelperSvc->cscIdHelper().get_id((IdentifierHash)stripHash,id,&channelContext);
543 int chamberLayer = m_idHelperSvc->cscIdHelper().chamberLayer(id);
544 char orientation = (m_idHelperSvc->cscIdHelper().measuresPhi(id) ? 'Y':'X');
545
546 int wireLayer = m_idHelperSvc->cscIdHelper().wireLayer(id);
547
548
549 int stationName = m_idHelperSvc->cscIdHelper().stationName(id);
550 int stationPhi = m_idHelperSvc->cscIdHelper().stationPhi(id);
551 int stationEta = m_idHelperSvc->cscIdHelper().stationEta(id);
552 int stripNumber = m_idHelperSvc->cscIdHelper().strip(id);
553
554 IdentifierHash chamHash;
555 m_idHelperSvc->cscIdHelper().get_module_hash(id,chamHash);
556
557 if(chamberLayer != m_expectedChamberLayer)
558 continue;
559
561 {
562 if(m_peakTimeProf->GetBinEntries(stripHash+1)) //See if any peaking times were recorded for strip
563 {
564 float peakt = m_peakTimeProf->GetBinContent(stripHash+1);
565 float peaktError = m_peakTimeProf->GetBinError(stripHash+1);
566 CscCalibResult * peaktResult = new CscCalibResult(stripHash,peakt, peaktError);
567 m_peakTimes->push_back(peaktResult);
568 }
569 }//end if(m_findPeakTime)
570
571 //Don't find slope for this strip if it is a transverse strip
572 if(orientation != 'X')
573 continue;
574
575 //For removing plateau's from fit
576 bool foundMin(false);
577 double fitMinX = 0;
578 double fitMaxX = 0;
579 double lastVal = -1;
580 double lastDrop=0;
581 double thisDrop=0;
582
583
584 TGraphErrors * calGraph = new TGraphErrors(numCalibPoints); //calGraph will be what the gain will be found on
585 char calName[20],titleSeed[500];
586 sprintf(calName, "calGraph%u",stripHash);
587 sprintf(titleSeed, "Calgraph for eta %d, sector %d, layer %d%c, strip %d",stationEta,(2*stationPhi+50 - stationName),wireLayer,orientation, stripNumber);
588 calGraph->SetName(calName);
589 std::string title = m_titlePrefix + titleSeed + m_titlePostfix;
590 calGraph->SetTitle(title.c_str());
591 calGraph->GetYaxis()->SetTitle("ADC counts");
592 calGraph->GetXaxis()->SetTitle("Attenuation (-db)");
593
594 ATH_MSG_DEBUG(" Generating " << title);
595
596 bool isGoodStrip = false;
597
598 //Loop over all attenuation levels, filling the calGraph with the amplitudes
599 //for this strip
600 ATH_MSG_DEBUG("Number of ampProfs " << m_ampProfs.size());
601 int calPointItr = 0;
602 for(const auto & [pulserLevel, pAmplitudeProfile] : m_ampProfs)
603 {
604 if(!pAmplitudeProfile){
605 ATH_MSG_FATAL("Failed at accessing ampProf!");
606 return StatusCode::FAILURE;
607 }
608 ATH_MSG_DEBUG("\tLooking for data for pulser level "
609 << pulserLevel);
610
611 if(pAmplitudeProfile->GetBinEntries(stripHash+1))
612 {
613
614 ATH_MSG_VERBOSE("\nHave data for strip " << stripHash);
615
616 isGoodStrip = true;
617
618
619 float adcValue = pAmplitudeProfile->GetBinContent(stripHash+1);
620 float adcError = pAmplitudeProfile->GetBinError(stripHash+1);
622 {
623 ATH_MSG_VERBOSE("\tCrosstalk fix " << m_crossTalkFix[crossTalkCnt]);
624 adcValue /= m_crossTalkFix[crossTalkCnt];
625 adcError /= m_crossTalkFix[crossTalkCnt];
626 }
627 if(adcError != adcError)
628 adcError = 0.01;
629
630 float db = m_dbLevels[pulserLevel];
631
632
633 float attenValue =0;
634 if(m_doLinPlot)
635 attenValue = 300*std::pow(10,db/20);
636 else
637 attenValue = db;
638
639 ATH_MSG_DEBUG("\tStoring at db of " << db << " with attenValue " << attenValue << " from pulser level of " << pulserLevel << " and adcValue " << adcValue);
640
641
642
643 //See if the last two drops were far down enough
644 if(!foundMin){
645 thisDrop = lastVal - adcValue;
646 ATH_MSG_DEBUG("\tFinding fit min:"
647 << "\tlastVal = " << lastVal
648 << ";lastDrop " << lastDrop << "; thisDrop " << thisDrop);
649 if(thisDrop > m_minDeltaAdc && lastDrop > m_minDeltaAdc){
650 ATH_MSG_DEBUG("Found fitMin!");
651 foundMin = true;
652 fitMinX = attenValue;
653 }
654 else{
655 //Not enough deltaADC, store this iterations values for the next loop
656 lastDrop = thisDrop;
657 lastVal = adcValue;
658 }
659 }
660
661 //Use highest attenuation level as fitMaxX
662 if(attenValue > fitMaxX)
663 fitMaxX = attenValue;
664
665 calGraph->SetPoint(calPointItr,attenValue,adcValue);
666 calGraph->SetPointError(calPointItr,0.01,adcError);
667 calPointItr++;
668 }//done if(entries >0)
669
670 }//Done ampProfItr loop
671
672 if(!foundMin && isGoodStrip){
673 ATH_MSG_WARNING("Failed to find minium for " << title);
674 }
675
676 //***Do a simple fit to calGraph***
677 //Here we only fit the linear part of the plot. m_fitCutoff can be set by user.
678 if(isGoodStrip)
679 {
680 ATH_MSG_INFO("we have a good stripHash at " << stripHash);
681
682 m_pulsedChambers.insert(chamHash); //Programer note: Only gets filled on x-axis. Probably OK.
683
684 float slope, slopeError, intercept, interceptError, chiSquared;
685 int ndf;
686 int fitRet=0;
687
688 //Setup our gain fit function
689 TF1 myFunc("myFunction", m_calFitFunc.c_str(), fitMinX, fitMaxX);
690 myFunc.SetLineColor(kRed);
691 if(m_doLinPlot)
692 {
693 myFunc.SetParameters(0,5);
694 slope = myFunc.GetParameter(1);
695 slopeError = myFunc.GetParError(1);
696 intercept = myFunc.GetParameter(0);
697 interceptError = myFunc.GetParError(0);
698 chiSquared = myFunc.GetChisquare();
699 ndf = myFunc.GetNDF();
700 }
701 else
702 {
703 myFunc.SetParameters(0.1,2000);
704
705 fitRet = calGraph->Fit(&myFunc,"RV");
706
707 slope = myFunc.GetParameter(1)/chargeMax;
708 slopeError = myFunc.GetParError(1);
709 intercept = myFunc.GetParameter(0);
710 interceptError = myFunc.GetParError(0);
711 chiSquared = myFunc.GetChisquare();
712 ndf = myFunc.GetNDF();
713 }
714
715 float invertedSlope;
716 if(std::abs(slope) < 0.00001 || slope == -999) //watch out for slope==0
717 {
718 ATH_MSG_WARNING("Slope invalid ");
719 continue;
720 }
721
722 invertedSlope = 1/slope;
723
724 ATH_MSG_ERROR("Inserting calgraph in for hash " << stripHash);
725 m_calGraphs[stripHash] = calGraph;
726
727 ATH_MSG_DEBUG("StripHash: " << stripHash << "; slope: " <<slope
728 << "; intercept: " << intercept
729 << "; chi^2/ndf: " << chiSquared << "/" << ndf);
730 CscCalibResult * slopeResult = new CscCalibResult(stripHash,invertedSlope,slopeError,chiSquared,ndf);
731 CscCalibResult * interceptResult = new CscCalibResult(stripHash, intercept, interceptError, chiSquared, ndf);
732
733 m_slopes->push_back(slopeResult);
734 m_intercepts->push_back(interceptResult);
735 m_fitReturns[stripHash] = fitRet;
736
737 }//end if(isGoodStrip)
738
739
740 if(crossTalkCnt == 23)
741 crossTalkCnt = 0;
742 else
743 crossTalkCnt++;
744 ATH_MSG_DEBUG("Looping over next strip...");
745 }//end loop over strips
746 ATH_MSG_INFO("Completed calculating parameters for each strip");
747 return StatusCode::SUCCESS;
748 }//End calculateParameters()
749
750 //writeCalibrationFile() dumps the parameters to disk
752 {
753 Chrono chrono(m_chronoSvc,"writeCalibrationFile");
754 if(m_calOutputVersion == "00-00"){
755 ATH_MSG_INFO("Printing output file version 00-00");
756 return calOutput0();
757 }
758 else if(m_calOutputVersion == "03-00") {
759 ATH_MSG_INFO("Printing output file version 03-00");
760 return calOutput3();
761 }
762 else{
763 ATH_MSG_INFO("Don't know how to write calibration file version " << m_calOutputVersion);
764 return StatusCode::RECOVERABLE;
765 }
766 }
767
769 //***Take conditions data held in summary histograms and print to the calibration file***//
770 ATH_MSG_INFO("Parameters calculated, preparing to outputing to file: " << m_outputFileName);
771 std::ofstream out;
772 out.open(m_outputFileName.c_str());
773 if(!out.is_open())
774 {
775 ATH_MSG_FATAL("Can't open file " << m_outputFileName.c_str() << "for writing");
776 return StatusCode::FAILURE;
777 }
778 //Start by writing file version number (mainly for COOL program to read)
779 out << "00-00 ";
780 //Number of strips we have info for:
781 out << m_slopes->size() << " ";
782 //print out header
783 out << "pslope ";
784 if(m_findPeakTime) out << "peakt ";
785 out << "END_HEADER\n";
786 //Now we loop over each strip's parameters and print them out
787 ATH_MSG_DEBUG("Begining loop over all " << m_maxStripHash << " hash ids.");
788
789 //form is:
790 //hashID chamber LayerOrientationStrip parametervalue parametervalue
796 {
797 peaktItr = m_peakTimes->begin();
798 peaktEnd = m_peakTimes->end();
799 }
800 for(; slopeItr != slopeEnd; ++slopeItr)
801 {
802 if(m_findPeakTime && (peaktItr == peaktEnd) )
803 {
804 ATH_MSG_FATAL("Peaktimes out of sync with slopes. Quiting write.");
805
806 return StatusCode::FAILURE;
807 }
808
809 //Output hashId
810 out << (*slopeItr)->hashId();
811
812 //get id for next few outputs
813 Identifier id;
814 IdContext channelContext = m_idHelperSvc->cscIdHelper().channel_context();
815 m_idHelperSvc->cscIdHelper().get_id((*slopeItr)->hashId(),id, &channelContext);
816
817 //output chamber #
818 IdentifierHash chamberHash;
819 Identifier chamberId = m_idHelperSvc->cscIdHelper().elementID(id);
820 if(!m_idHelperSvc->cscIdHelper().valid(chamberId))
821 {
822 ATH_MSG_FATAL(chamberId.getString() << " is not a valid id!");
823 ATH_MSG_FATAL("identifier is: " << m_idHelperSvc->cscIdHelper().show_to_string(chamberId));
824 return StatusCode::FAILURE;
825 }
826
827 m_idHelperSvc->cscIdHelper().get_module_hash(id,chamberHash);
828 out <<" " << chamberHash;
829
830 //output strip details
831 out << " " << m_idHelperSvc->cscIdHelper().show_to_string(id) << " ";
832
833 //output parameter values
834 out << " " << (*slopeItr)->value();
835 if(m_findPeakTime) out << " " << (*peaktItr)->value();
836 out << "\n" ; //to improve readability
837 } //end loop over hash Ids
838
839 out.close(); //done writing
840
841 return StatusCode::SUCCESS;
842 }//end calOutput0
843
845 {
846 ATH_MSG_INFO("Recording csc calibration report.");
847
848 StatusCode sc = StatusCode::SUCCESS;
849
850 bool thereIsAnError = false;
851
852 std::string histKey = "cscSlopeCalibReport";
853 ATH_MSG_DEBUG("Recording calibration graphs to TDS with key " << histKey);
854
855 CscCalibReportSlope * report = new CscCalibReportSlope("calGraphs");
856
857 report->setCalGraphs(std::move(m_calGraphs));
858 report->setAmpProfs(std::move(m_ampProfs));
859 report->setPulsedChambers(std::move(m_pulsedChambers));
860 report->setBitHists(std::move(m_bitHists));
861 report->setFitResults(std::move(m_fitReturns));
862
863 CscCalibReportContainer * repCont = new CscCalibReportContainer(histKey);
864 repCont->push_back(report);
865
866 sc = evtStore()->record(repCont, histKey);
867 if(sc.isFailure())
868 {
869 ATH_MSG_ERROR("Failed to record CscCalibReportSlope to storegate");
870 thereIsAnError = true;
871 //Since storegate isn't taking ownership, we'll delete it:
872 delete repCont;
873 }
874
875 CscCalibResultContainer * calibResults
876 = new CscCalibResultContainer("CscCalibResultSlope");
877 calibResults->push_back(m_slopes);
878 calibResults->push_back(m_intercepts);
880 calibResults->push_back(m_peakTimes);
881 sc = evtStore()->record(calibResults,"CscCalibResultSlope");
882 if(sc.isFailure())
883 {
884 ATH_MSG_ERROR("Failed to record results to storegate");
885 thereIsAnError = true;
886 //Since storegate isn't taking ownership, we'll delete it
887 delete calibResults;
888 }
889
890 if(thereIsAnError)
891 return StatusCode::RECOVERABLE;
892
893 return StatusCode::SUCCESS;
894 }
895
896
897
899 std::ofstream out;
900 out.open(m_outputFileName.c_str());
901 if(!out.is_open())
902 {
903 ATH_MSG_ERROR("Can't open file " << m_outputFileName.c_str());
904 return StatusCode::RECOVERABLE;
905 }
906 out << "03-00 <END_HEADER>";
907
909 out << "\n<END_FILE>";
910 out.close();
911
912 ATH_MSG_INFO("Successfully opened file " << m_outputFileName);
913
914 return StatusCode::SUCCESS;
915 }
916
917
918 void CscCalcSlope::outputParameter3(const CscCalibResultCollection & results, std::ofstream & out){
919 ATH_MSG_INFO("Printing out parameter " << results.parName());
920
922 const CscCondDbData* readCdo{*readHandle};
923
924 out << "\n";
925 out << "<NEW_PAR> " << results.parName() << "\n";
926 std::string idString;
927
928 CscCalibResultCollection::const_iterator resItr = results.begin();
929 CscCalibResultCollection::const_iterator resEnd = results.end();
930 for(; resItr != resEnd; ++resItr){
931 unsigned int hashId = (*resItr)->hashId();
932 double value = (*resItr)->value();
933 std::string idString;
934
935 readCdo->indexToStringId(&m_idHelperSvc->cscIdHelper(), hashId, "CHANNEL", idString).ignore();
936
937 out << idString << " " << value << "\n";
938 }
939
940 out << "<END_PAR>" ;
941 }
942}//end namespace MuonCalib
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_FATAL(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
static Double_t sc
const double width
AthAlgorithm(const std::string &name, ISvcLocator *pSvcLocator)
Constructor with parameters:
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
StatusCode indexToStringId(const CscIdHelper *, const unsigned int &, const std::string &, std::string &) const
StatusCode readChannelPed(IdentifierHash, float &) const
StatusCode readChannelNoise(IdentifierHash, float &) const
This container provides access to collections of CSC RDOs and a mechanism for recording them.
DataModel_detail::const_iterator< DataVector > const_iterator
Definition DataVector.h:838
value_type push_back(value_type pElem)
Add an element to the end of the collection.
DataModel_detail::iterator< DataVector > iterator
Definition DataVector.h:842
This class saves the "context" of an expanded identifier (ExpandedIdentifier) for compact or hash ver...
Definition IdContext.h:26
This is a "hash" representation of an Identifier.
std::string getString() const
Provide a string form of the identifier - hexadecimal.
std::set< int > m_pulsedChambers
StatusCode initialize(void)
basic required functions
std::string m_outputFileName
Parameters input through joboptions.
CscCalibResultCollection * m_peakTimes
std::array< double, 24 > m_crossTalkFix
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
SG::ReadCondHandleKey< CscCondDbData > m_readKey
CscCalibResultCollection * m_intercepts
StatusCode finalize(void)
std::vector< TGraphErrors * > m_calGraphs
StatusCode calculateParameters()
Finalize functions.
CscCalibResultCollection * m_slopes
std::string m_calOutputVersion
ToolHandle< ICscCalibTool > m_cscCalibTool
Services and tools.
int m_eventCnt
coherent correction array has the corrections to the coherently pulsed channels to get the basic chan...
std::map< int, TProfile * > m_ampProfs
DataVector< DataVector< TProfile > > * m_fracProfs
StatusCode execute(void)
unsigned int m_maxStripHash
Internally global variables.
StatusCode fillBitHist(TH1I *bitHist, const uint16_t &val)
CscCalcSlope(const std::string &name, ISvcLocator *pSvcLocator)
ToolHandle< Muon::ICSC_RDO_Decoder > m_cscRdoDecoderTool
void outputParameter3(const CscCalibResultCollection &results, std::ofstream &out)
std::vector< float > m_dbLevels
std::vector< TH1I * > m_bitHists
std::vector< float > m_fitReturns
DataVector< DataVector< TGraph > > * m_fracGraphs
SmartIF< IChronoStatSvc > m_chronoSvc
StatusCode collectEventInfo()
event loop functions
StatusCode writeCalibrationFile()
double chi2(TH1 *h0, TH1 *h1)
CscCalcPed - algorithm that finds the Cathode Strip Chamber pedestals from an RDO.