File indexing completed on 2025-08-05 08:12:21
0001 #include "CaloTemplateFit.h"
0002
0003 #include "PROTOTYPE4_FEM.h"
0004 #include "RawTower_Prototype4.h"
0005
0006 #include <calobase/RawTower.h> // for RawTower
0007 #include <calobase/RawTowerContainer.h>
0008 #include <calobase/RawTowerDefs.h> // for keytype
0009
0010 #include <phparameter/PHParameters.h> // for PHParameters
0011
0012 #include <fun4all/Fun4AllReturnCodes.h>
0013 #include <fun4all/SubsysReco.h> // for SubsysReco
0014
0015 #include <phool/PHCompositeNode.h>
0016 #include <phool/PHIODataNode.h> // for PHIODataNode
0017 #include <phool/PHNode.h> // for PHNode
0018 #include <phool/PHNodeIterator.h> // for PHNodeIterator
0019 #include <phool/PHObject.h> // for PHObject
0020 #include <phool/getClass.h>
0021
0022 #include <boost/format.hpp>
0023
0024 #include <cassert>
0025 #include <cmath> // for NAN, isnan
0026 #include <cstdlib> // for exit
0027 #include <iostream>
0028 #include <limits> // for numeric_limits
0029 #include <map> // for map, _Rb_tree_iter...
0030 #include <stdexcept> // for runtime_error
0031 #include <string>
0032 #include <utility> // for pair
0033 #include <vector> // for vector
0034 #include <TProfile.h>
0035
0036 #include <pthread.h>
0037 #include <TFile.h>
0038 #include <ROOT/TThreadExecutor.hxx>
0039 #include <ROOT/TThreadedObject.hxx>
0040 #include <iostream>
0041 #include "TThread.h"
0042 #include "TMutex.h"
0043 #include "TMath.h"
0044
0045 #include "Math/WrappedTF1.h"
0046 #include "Math/WrappedMultiTF1.h"
0047 #include "Fit/BinData.h"
0048 #include "Fit/UnBinData.h"
0049 #include "HFitInterface.h"
0050 #include "Fit/Fitter.h"
0051 #include "Fit/Chi2FCN.h"
0052 #include <pthread.h>
0053 #include "Math/Functor.h"
0054 #include <TH1F.h>
0055 using namespace std;
0056
0057
0058
0059
0060
0061 double CaloTemplateFit::template_function(double *x, double *par)
0062 {
0063 Double_t v1 = par[0]*h_template->Interpolate(x[0]-par[1])+par[2];
0064
0065 return v1;
0066 }
0067
0068
0069
0070
0071 std::vector<std::vector<float>> CaloTemplateFit::calo_processing_perchnl(std::vector<std::vector<float>> chnlvector)
0072 {
0073 ROOT::TThreadExecutor t(_nthreads);
0074 auto func = [&](std::vector<float> &v) {
0075 int size1 = v.size()-1;
0076 auto h = new TH1F(Form("h_%d",(int)round(v.at(size1))),"",size1,0,size1);
0077 float maxheight = 0;
0078 int maxbin = 0;
0079 for (int i = 0; i < size1;i++)
0080 {
0081 h->SetBinContent(i+1,v.at(i));
0082 if (v.at(i)>maxheight)
0083 {
0084 maxheight = v.at(i);
0085 maxbin = i;
0086 }
0087 }
0088 float pedestal = 1500;
0089 if (maxbin > 4)
0090 {
0091 pedestal= 0.5* ( v.at(maxbin - 4) + v.at(maxbin-5));
0092 }
0093 else if (maxbin > 3)
0094 {
0095 pedestal=( v.at(maxbin - 4));
0096 }
0097 else
0098 {
0099 pedestal = 0.5* ( v.at(size1-3) + v.at(size1-2));
0100 }
0101 auto f = new TF1(Form("f_%d",(int)round(v.at(size1))),template_function,0,31,3);
0102 ROOT::Math::WrappedMultiTF1 * fitFunction = new ROOT::Math::WrappedMultiTF1(*f, 3 );
0103 ROOT::Fit::BinData data(v.size()-1,1);
0104 ROOT::Fit::FillData(data,h);
0105 ROOT::Fit::Chi2Function *EPChi2 = new ROOT::Fit::Chi2Function(data, *fitFunction);
0106 ROOT::Fit::Fitter *fitter = new ROOT::Fit::Fitter();
0107 fitter->Config().MinimizerOptions().SetMinimizerType("GSLMultiFit");
0108 double params[] = {static_cast<double>(maxheight),static_cast<double>(maxbin-5),static_cast<double>(pedestal)};
0109 fitter->Config().SetParamsSettings(3,params);
0110 fitter->FitFCN(*EPChi2,0,data.Size(),true);
0111 for (int i =0;i<3;i++)
0112 {
0113 v.push_back(f->GetParameter(i));
0114 }
0115 h->Delete();
0116 f->Delete();
0117 delete fitFunction;
0118 delete fitter;
0119 delete EPChi2;
0120
0121 };
0122
0123 t.Foreach(func, chnlvector);
0124
0125 int size3 = chnlvector.size();
0126 std::vector<std::vector<float>> fit_params;
0127 std::vector<float> fit_params_tmp;
0128 for (int i = 0; i < size3;i++)
0129 {
0130 std::vector<float> tv = chnlvector.at(i);
0131 int size2 = tv.size();
0132 for (int q = 3; q > 0;q--)
0133 {
0134 fit_params_tmp.push_back(tv.at(size2-q));
0135 }
0136 fit_params.push_back(fit_params_tmp);
0137 fit_params_tmp.clear();
0138 }
0139
0140
0141 chnlvector.clear();
0142 return fit_params;
0143 fit_params.clear();
0144 }
0145
0146
0147
0148
0149 std::vector<float> CaloTemplateFit::calo_processing_singlethread(std::vector<float> chnlvector)
0150 {
0151 int size1 = chnlvector.size();
0152 float maxheight = 0;
0153 int maxbin = 0;
0154 for (int i = 0; i < size1;i++)
0155 {
0156 h_data->SetBinContent(i+1,chnlvector.at(i));
0157 if (chnlvector.at(i)>maxheight)
0158 {
0159 maxheight = chnlvector.at(i);
0160 maxbin = i;
0161 }
0162 }
0163 float pedestal = 1500;
0164 if (maxbin > 4)
0165 {
0166 pedestal= 0.5* ( chnlvector.at(maxbin - 4) + chnlvector.at(maxbin-5));
0167 }
0168 else if (maxbin > 3)
0169 {
0170 pedestal=( chnlvector.at(maxbin - 4));
0171 }
0172 else
0173 {
0174 pedestal = 0.5* ( chnlvector.at(size1-3) + chnlvector.at(size1-2));
0175 }
0176 ROOT::Math::WrappedMultiTF1 fitFunction(*f_fit, 3 );
0177 ROOT::Fit::BinData data(chnlvector.size()-1,1);
0178 ROOT::Fit::FillData(data,h_data);
0179 ROOT::Fit::Chi2Function EPChi2(data, fitFunction);
0180 ROOT::Fit::Fitter fitter;
0181 fitter.Config().MinimizerOptions().SetMinimizerType("GSLMultiFit");
0182 double params[] = {static_cast<double>(maxheight),static_cast<double>(maxbin-5),static_cast<double>(pedestal)};
0183 fitter.Config().SetParamsSettings(3,params);
0184 fitter.FitFCN(EPChi2,0,data.Size(),true);
0185
0186 std::vector<float> fit_params;
0187 for (int q = 0; q < 3;q++)
0188 {
0189 fit_params.push_back(f_fit->GetParameter(q));
0190 }
0191 return fit_params;
0192
0193
0194 }
0195
0196
0197 TProfile* CaloTemplateFit::h_template = nullptr;
0198
0199
0200
0201
0202 CaloTemplateFit::CaloTemplateFit(const std::string &name)
0203 : SubsysReco(string("CaloCalibration_") + name)
0204 , _calib_towers(nullptr)
0205 , _raw_towers(nullptr)
0206 , detector(name)
0207 , _calib_tower_node_prefix("CALIB")
0208 , _raw_tower_node_prefix("RAW")
0209 , _nthreads(1)
0210 , _nsamples(0)
0211 , template_input_file("/gpfs/mnt/gpfs02/sphenix/user/trinn/fitting_algorithm_playing/prdfcode/prototype/offline/packages/Prototype4/templates.root")
0212 , _calib_params(name)
0213 , _fit_type(kPowerLawDoubleExpWithGlobalFitConstraint)
0214 {
0215 SetDefaultParameters(_calib_params);
0216 }
0217
0218
0219 int CaloTemplateFit::InitRun(PHCompositeNode *topNode)
0220 {
0221 CreateNodeTree(topNode);
0222
0223 if (Verbosity())
0224 {
0225 std::cout << Name() << "::" << detector << "::" << __PRETTY_FUNCTION__
0226 << " - print calibration parameters: " << endl;
0227 _calib_params.Print();
0228 }
0229
0230
0231 TFile* fin = TFile::Open(template_input_file.c_str());
0232 assert(fin);
0233 assert(fin->IsOpen());
0234 h_template = static_cast<TProfile*>(fin->Get("hp_electrons_fine_emcal_36_8GeV"));
0235 h_template->SetDirectory(0);
0236 fin->Close();
0237 delete fin;
0238
0239
0240 h_data = new TH1F("h_data","",32,0,32);
0241 f_fit = new TF1("f_fit",template_function,0,31,3);
0242
0243
0244 ROOT::EnableThreadSafety();
0245
0246 return Fun4AllReturnCodes::EVENT_OK;
0247 }
0248
0249
0250 int CaloTemplateFit::process_event(PHCompositeNode *topNode)
0251 {
0252 if (Verbosity())
0253 {
0254 std::cout << Name() << "::" << detector << "::" << __PRETTY_FUNCTION__
0255 << "Process event entered" << std::endl;
0256 }
0257
0258 map<int, double> parameters_constraints;
0259
0260 if ( _raw_towers->size() > 1)
0261 {
0262 if (Verbosity())
0263 {
0264 std::cout
0265 << Name() << "::" << detector << "::" << __PRETTY_FUNCTION__
0266 << "Extract global fit parameter for constraining individual fits"
0267 << std::endl;
0268 }
0269
0270 vector<float> waveforms;
0271 vector<vector<float>> waveforms2;
0272 int count = 0;
0273 RawTowerContainer::Range begin_end = _raw_towers->getTowers();
0274 RawTowerContainer::Iterator rtiter;
0275 for (rtiter = begin_end.first; rtiter != begin_end.second; ++rtiter)
0276 {
0277 RawTower_Prototype4 *raw_tower =
0278 dynamic_cast<RawTower_Prototype4 *>(rtiter->second);
0279 assert(raw_tower);
0280 ++count;
0281
0282 for (int i = 0; i < RawTower_Prototype4::NSAMPLES; i++)
0283 {
0284 if (i >= _nsamples && _nsamples != 0){continue;}
0285 waveforms.push_back(raw_tower->get_signal_samples(i));
0286 }
0287
0288
0289 waveforms.push_back(count);
0290 waveforms2.push_back(waveforms);
0291 waveforms.clear();
0292 }
0293 std::vector< std::vector<float>> pulse_quantification = calo_processing_perchnl(waveforms2);
0294
0295 int towernumber = 0;
0296
0297 for (rtiter = begin_end.first; rtiter != begin_end.second; ++rtiter)
0298 {
0299
0300 RawTower_Prototype4 *raw_tower =
0301 dynamic_cast<RawTower_Prototype4 *>(rtiter->second);
0302 assert(raw_tower);
0303
0304 if (std::isnan(raw_tower->get_energy()))
0305 {
0306
0307 std::vector<float> values = pulse_quantification.at(towernumber);
0308 raw_tower->set_energy(values.at(0));
0309 raw_tower->set_time(values.at(1));
0310 values.clear();
0311 }
0312 towernumber++;
0313 }
0314 pulse_quantification.clear();
0315 waveforms2.clear();
0316
0317 }
0318
0319
0320
0321
0322
0323
0324
0325
0326
0327
0328
0329
0330
0331
0332
0333
0334
0335
0336
0337
0338
0339
0340
0341
0342
0343
0344
0345
0346
0347
0348
0349
0350
0351
0352
0353
0354
0355
0356
0357
0358
0359
0360
0361
0362
0363
0364
0365
0366
0367
0368
0369
0370
0371
0372
0373
0374
0375
0376
0377
0378
0379
0380
0381
0382
0383
0384
0385
0386
0387
0388
0389
0390
0391
0392
0393
0394
0395
0396
0397
0398
0399
0400
0401
0402
0403
0404
0405
0406
0407
0408
0409
0410
0411
0412
0413
0414
0415
0416
0417
0418
0419
0420
0421
0422
0423
0424
0425
0426
0427
0428
0429
0430
0431
0432
0433
0434
0435
0436
0437
0438
0439
0440
0441
0442
0443
0444
0445
0446
0447
0448
0449
0450
0451
0452
0453
0454
0455
0456
0457
0458
0459
0460
0461
0462
0463
0464
0465
0466
0467
0468
0469
0470
0471
0472
0473
0474
0475
0476
0477
0478
0479
0480
0481
0482
0483
0484
0485
0486
0487
0488
0489
0490
0491
0492
0493
0494
0495
0496
0497 return Fun4AllReturnCodes::EVENT_OK;
0498 }
0499
0500
0501 void CaloTemplateFit::CreateNodeTree(PHCompositeNode *topNode)
0502 {
0503 PHNodeIterator iter(topNode);
0504
0505 PHCompositeNode *dstNode =
0506 dynamic_cast<PHCompositeNode *>(iter.findFirst("PHCompositeNode", "DST"));
0507 if (!dstNode)
0508 {
0509 std::cerr << Name() << "::" << detector << "::" << __PRETTY_FUNCTION__
0510 << "DST Node missing, doing nothing." << std::endl;
0511 throw std::runtime_error(
0512 "Failed to find DST node in RawTowerCalibration::CreateNodes");
0513 }
0514
0515 RawTowerNodeName = "TOWER_" + _raw_tower_node_prefix + "_" + detector;
0516 _raw_towers =
0517 findNode::getClass<RawTowerContainer>(dstNode, RawTowerNodeName.c_str());
0518 if (!_raw_towers)
0519 {
0520 std::cerr << Name() << "::" << detector << "::" << __PRETTY_FUNCTION__
0521 << " " << RawTowerNodeName << " Node missing, doing bail out!"
0522 << std::endl;
0523 throw std::runtime_error("Failed to find " + RawTowerNodeName +
0524 " node in RawTowerCalibration::CreateNodes");
0525 }
0526
0527
0528 PHNodeIterator dstiter(dstNode);
0529 PHCompositeNode *DetNode = dynamic_cast<PHCompositeNode *>(
0530 dstiter.findFirst("PHCompositeNode", detector));
0531 if (!DetNode)
0532 {
0533 DetNode = new PHCompositeNode(detector);
0534 dstNode->addNode(DetNode);
0535 }
0536
0537
0538
0539 CaliTowerNodeName = "TOWER_" + _calib_tower_node_prefix + "_" + detector;
0540 _calib_towers =
0541 findNode::getClass<RawTowerContainer>(DetNode, CaliTowerNodeName.c_str());
0542 if (!_calib_towers)
0543 {
0544 _calib_towers = new RawTowerContainer(_raw_towers->getCalorimeterID());
0545 PHIODataNode<PHObject> *towerNode = new PHIODataNode<PHObject>(
0546 _calib_towers, CaliTowerNodeName.c_str(), "PHObject");
0547 DetNode->addNode(towerNode);
0548 }
0549
0550
0551 PHCompositeNode *parNode =
0552 dynamic_cast<PHCompositeNode *>(iter.findFirst("PHCompositeNode", "RUN"));
0553 assert(parNode);
0554 const string paramnodename = string("Calibration_") + detector;
0555
0556
0557
0558 _calib_params.SaveToNodeTree(parNode, paramnodename);
0559 }
0560
0561 void CaloTemplateFit::SetDefaultParameters(PHParameters ¶m)
0562 {
0563 param.set_int_param("use_chan_calibration", 0);
0564
0565
0566
0567 param.set_double_param("calib_const_scale", 1);
0568 }