Neutral Particle Spectrometer analysis code
Loading...
Searching...
No Matches
THcNPSCalorimeter.cxx
Go to the documentation of this file.
1
8#include "THcNPSCalorimeter.h"
10#include "THcRawShowerHit.h"
11#include "THaEvData.h"
12#include "THaDetMap.h"
13#include "THcDetectorMap.h"
14#include "THcGlobals.h"
15#include "THaCutList.h"
16#include "THcParmList.h"
17#include "THcNPSCluster.h"
18#include "VTPModule.h"
19#include "VLDModule.h"
20#include "VarDef.h"
21#include "VarType.h"
22#include "THaTrack.h"
23#include "TClonesArray.h"
24#include "THaTrackProj.h"
25#include "TMath.h"
26#include "Helper.h"
27#include "TRandom.h"
28
29#include <cstring>
30#include <cstdio>
31#include <cstdlib>
32#include <iostream>
33#include <numeric>
34#include <cassert>
35
36using namespace std;
37
38//_____________________________________________________________________________
39THcNPSCalorimeter::THcNPSCalorimeter( const char* name, const char* description,
40 THaApparatus* apparatus ) :
41 THaNonTrackingDetector(name,description,apparatus),
42 // fClusterList(0), fLayerNames(0), fLayerZPos(0), BlockThick(0),
43 //fNBlocks(0),
44 //fXPos(0), fYPos(0), fZPos(0),
45 fCalReplicate(0), fAnalyzer(0), fArray(0)
46{
47
48 //cout << "Calling Constructor | THcNPSCalorimeter::THcNPSCalorimeter() . . . " << endl;
49
50 fVTPErrorFlag = 0;
51 fVLDErrorFlag = 0;
52
53 // Constructor
54 // fNLayers = 0; // No layers until we make them
55 fNTotLayers = 0;
56 fHasArray = 0;
57
59}
60
61//_____________________________________________________________________________
64 fClusterList(0), fLayerNames(0),
65 //fLayerZPos(0), BlockThick(0),
66 //fNBlocks(0),
67 //fXPos(0), fYPos(0), fZPos(0),
68 fArray(0)
69{
70 // Constructor
71}
72
73//_____________________________________________________________________________
74void THcNPSCalorimeter::Setup(const char* name, const char* description)
75{
76 // cout<< "Calling THcNPSCalorimeter::Setup() . . ." << endl;
77
78 //Get apparatus prefix name
79 string kwPrefix = GetApparatus()->GetName();
80 std::transform(kwPrefix.begin(), kwPrefix.end(), kwPrefix.begin(), ::tolower);
81 fKwPrefix = kwPrefix;
82
83 string layernamelist;
84 fHasArray = 0; // Flag for presence of fly's eye array
85 fCalReplicate = 0;
86 DBRequest list[]={
87 // {"cal_num_layers", &fNLayers, kInt},
88 {"_cal_arr_nrows", &fNRows, kInt},
89 {"_cal_arr_ncolumns", &fNColumns, kInt},
90 {"_cal_layer_names", &layernamelist, kString},
91 {"_cal_array",&fHasArray, kInt,0, 1},
92 {"_cal_adcrefcut", &fADC_RefTimeCut, kInt, 0, 1},
93 {"_cal_replicate", &fCalReplicate, kInt, 0, 1},
94 {0}
95 };
96
98 gHcParms->LoadParmValues((DBRequest*)&list,fKwPrefix.c_str());
99 // fNTotLayers = (fNLayers+(fHasArray!=0?1:0));
100 fNTotLayers = (fHasArray!=0?1:0);
101 vector<string> layer_names = Podd::vsplit(layernamelist);
102
103 if(layer_names.size() != fNTotLayers) {
104 cout << "THcNPSCalorimeter::Setup ERROR: Number of layers " << fNTotLayers
105 << " doesn't agree with number of layer names "
106 << layer_names.size() << endl;
107 // Should quit. Is there an official way to quit?
108 }
109
110 fLayerNames = new char* [fNTotLayers];
111 for(UInt_t i=0;i<fNTotLayers;i++) {
112 fLayerNames[i] = new char[layer_names[i].length()+1];
113 strcpy(fLayerNames[i], layer_names[i].c_str());
114 }
115
116 char *desc = new char[strlen(description)+100];
117 // fPlanes = new THcShowerPlane* [fNLayers];
118
119 if(fHasArray) {
120 strcpy(desc, description);
121 strcat(desc, " Array ");
122 strcat(desc, fLayerNames[fNTotLayers-1]);
123
125 this);
126 } else {
127 fArray = 0;
128 }
129
130 delete [] desc;
131
132 // cout << "---------------------------------------------------------------\n";
133
134 // if(fHasArray)
135 // cout << fLayerNames[fNTotLayers-1] << " has fly\'s eye configuration\n";
136
137 // cout << "---------------------------------------------------------------\n";
138
139}
140
141
142//_____________________________________________________________________________
144{
145
146 // cout<< "Calling THcNPSCalorimeter::Init() . . ." << endl;
147
148 Setup(GetName(), GetTitle());
149
150 // DJH 09/04/22 -- only create dedicated analyzer object if using SHMS data
151 if(fCalReplicate==0)
153
154 string kwPrefix = GetApparatus()->GetName();
155 //std::transform(kwPrefix.begin(), kwPrefix.end(), kwPrefix.begin(), ::toupper);
156
157 const char* EngineDID = Form("%sCAL", kwPrefix.c_str());
158 if( gHcDetectorMap->FillMap(fDetMap, EngineDID) < 0 ) {
159 static const char* const here = "Init()";
160 Error( Here(here), "Error filling detectormap for %s.", EngineDID );
161 return kInitError;
162 }
163
164 // Should probably put this in ReadDatabase as we will know the
165 // maximum number of hits after setting up the detector map
166
167 InitHitList(fDetMap, "THcRawShowerHit", fDetMap->GetTotNumChan()+1,
168 0, fADC_RefTimeCut);
169
170 EStatus status;
171 if( (status = THaNonTrackingDetector::Init( date )) )
172 return fStatus=status;
173
174 if(fHasArray) {
175 if((status = fArray->Init( date ))) {
176 return fStatus = status;
177 }
178 }
179
180 if(fHasArray) {
181 // cout << "THcShower::Init: adjustment of fiducial volume limits to the fly's eye part." << endl;
182 // cout << " Old limits:" << endl;
183 // cout << " Xmin = " << fvXmin << " Xmax = " << fvXmax << endl;
184 // cout << " Ymin = " << fvYmin << " Ymax = " << fvYmax << endl;
189 // cout << " New limits:" << endl;
190 // cout << " Xmin = " << fvXmin << " Xmax = " << fvXmax << endl;
191 // cout << " Ymin = " << fvYmin << " Ymax = " << fvYmax << endl;
192 }
193
194 // cout << "---------------------------------------------------------------\n";
195 // cout << "From THcShower::Init: initialized " << GetApparatus()->GetName()
196 // << GetName() << endl;
197 // cout << "---------------------------------------------------------------\n";
198
199 fPresentP = 0;
200 THaVar* vpresent = gHaVars->Find(Form("%s.present",GetApparatus()->GetName()));
201 if(vpresent) {
202 fPresentP = (Bool_t *) vpresent->GetValuePointer();
203 }
204 return fStatus = kOK;
205}
206
207//_____________________________________________________________________________
209{
210 // cout<< "Calling THcNPSCalorimeter::ReadDatabase() . . ." << endl;
211
212 // Read this detector's parameters from the database file 'fi'.
213 // This function is called by THaDetectorBase::Init() once at the
214 // beginning of the analysis.
215 // 'date' contains the date/time of the run being analyzed.
216
217 // static const char* const here = "ReadDatabase()";
218
219 // Read data from database
220 // Pull values from the THcParmList instead of reading a database
221 // file like Hall A does.
222
223 // We will probably want to add some kind of method to gHcParms to allow
224 // bulk retrieval of parameters of interest.
225
226 // Will need to determine which spectrometer in order to construct
227 // the parameter names (e.g. hscin_1x_nr vs. sscin_1x_nr)
228
229 CreateMissReportParms(Form("%s_cal",fKwPrefix.c_str()));
230
231 //fNegCols = fNLayers; // If not defined assume tube on each end
232 // for every layer
233 {
234 DBRequest list[]={
235 // {"_cal_num_neg_columns", &fNegCols, kInt, 0, 1},
236 {"_cal_clustering", &fClustMethod, kInt, 0, 1},
237 {"_cal_make_grid", &fMakeGrid, kInt, 0, 1},
238 {"_cal_slop", &fSlop, kDouble,0,1},
239 {"_cal_fv_test", &fvTest, kInt,0,1},
240 {"_cal_fv_delta", &fvDelta, kDouble,0,1},
241 {"_cal_ADCMode", &fADCMode, kInt, 0, 1},
242 {"_cal_cluster_time_window", &fClusterTimeWindow, kDouble, 0, 1},
243 {"_cal_adc_tdc_offset", &fAdcTdcOffset, kDouble, 0, 1},
244 {"_dbg_raw_cal", &fdbg_raw_cal, kInt, 0, 1},
245 {"_dbg_decoded_cal", &fdbg_decoded_cal, kInt, 0, 1},
246 {"_dbg_sparsified_cal", &fdbg_sparsified_cal, kInt, 0, 1},
247 {"_dbg_clusters_cal", &fdbg_clusters_cal, kInt, 0, 1},
248 {"_dbg_tracks_cal", &fdbg_tracks_cal, kInt, 0, 1},
249 {"_dbg_init_cal", &fdbg_init_cal, kInt, 0, 1},
250 {0}
251 };
252 fClustMethod = 0; //Set default clustering method to HMS/SHMS original
253 fMakeGrid = 0; //Default if not defined
254 fvTest = 0; // Default if not defined
255 fdbg_raw_cal = 0; // Debugging off by default
259 fdbg_tracks_cal = 0;
260 fdbg_init_cal = 0;
261 fClusterTimeWindow = 40.0; //Cluster time window set to +-40.0ns from cluster time
262 fAdcTdcOffset=0.0;
264 gHcParms->LoadParmValues((DBRequest*)&list, fKwPrefix.c_str());
265 }
266
267 // Debug output.
268 if (fdbg_init_cal) {
269 cout << "---------------------------------------------------------------\n";
270 cout << "Debug output from THcNPSCalorimeter::ReadDatabase for "
271 << GetApparatus()->GetName() << endl;
272
273 cout << " Number of neg. columns = " << fNegCols << endl;
274 cout << " Slop parameter = " << fSlop << endl;
275 cout << " Fiducial volume test flag = " << fvTest << endl;
276 cout << " Fiducial volume excl. width = " << fvDelta << endl;
277 cout << " Initialize debug flag = " << fdbg_init_cal << endl;
278 cout << " Raw hit debug flag = " << fdbg_raw_cal << endl;
279 cout << " Decode debug flag = " << fdbg_decoded_cal << endl;
280 cout << " Sparsify debug flag = " << fdbg_sparsified_cal << endl;
281 cout << " Cluster debug flag = " << fdbg_clusters_cal << endl;
282 cout << " Tracking debug flag = " << fdbg_tracks_cal << endl;
283 }
284
285 //C.Y. Feb 22, 2021: Define output .csv file to write grid
286 if(fMakeGrid){
287 fOutFile = new ofstream;
288
289
290 //Write header if using Standard HMS/SHMS Algorithm
291 //(developed by Tsolak Amatuni some time before 1995, and re-written by Vardan T. in ROOT C++)
292 if(fClustMethod == 0){
293
294 //fOutFile->open("SHMS_Standard_Cal_Grid.csv");
295 cout << "Clustering Algorithm: HCANA STANDARD " << endl;
296 if(fCalReplicate==0) { fOutFile->open("SHMS_Standard_Cal_Grid.csv"); }
297 else if(fCalReplicate>0) { fOutFile->open("NPS_Standard_Cal_Grid.csv"); }
298 //Write header information
299
300 *fOutFile << "#! evNum[i,0]/, \t Nclusters[i,1]/, \t iCluster[i,2]/, \t BlockID[i,3]/, \t fT[f,4]/, \t fPI[f,5]/, \t fE[f,6]/" << endl;
301
302 }
303
304 //Write header if using Cellular Automata Clustering Algorithm (Same approach used in Hall A DVCS)
305 if(fClustMethod == 1){
306
307 //fOutFile->open("SHMS_CellularAutomata_Cal_Grid.csv");
308 cout << "Clustering Algorithm: CELLULAR AUTOMATA " << endl;
309 if(fCalReplicate==0) { fOutFile->open("SHMS_CellularAutomata_Cal_Grid.csv"); }
310 else if(fCalReplicate>0) { fOutFile->open("NPS_CellularAutomata_Cal_Grid.csv"); }
311 //Write header information
312 *fOutFile << "#! evNum[i,0]/, \t Nclusters[i,1]/, \t iCluster[i,2]/, \t BlockID[i,3]/, \t fT[f,4]/, \t fPI[f,5]/, \t fE[f,6]/" << endl;
313
314 }
315
316
317
318 }
319
320 /*---- C.Y. I think these can be removed (check with S. Wood)
321 {
322 DBRequest list[]={
323 {"_cal_a_cor", &fAcor, kDouble},
324 {"_cal_b_cor", &fBcor, kDouble},
325 {"_cal_c_cor", fCcor, kDouble, 2},
326 {"_cal_d_cor", fDcor, kDouble, 2},
327 {0}
328 };
329 gHcParms->LoadParmValues((DBRequest*)&list, fKwPrefix.c_str());
330 }
331
332 // Debug output.
333 if (fdbg_init_cal) {
334 cout << " Coordinate correction constants:\n";
335 cout << " fAcor = " << fAcor << endl;
336 cout << " fBcor = " << fBcor << endl;
337 cout << " fCcor = " << fCcor[0] << ", " << fCcor[1] << endl;
338 cout << " fDcor = " << fDcor[0] << ", " << fDcor[1] << endl;
339 }
340 -------------------*/
341
342 // BlockThick = new Double_t [fNLayers];
343 // fNBlocks = new UInt_t [fNLayers];
344 // fLayerZPos = new Double_t [fNLayers];
345 // fYPos = new Double_t [2*fNLayers];
346
347 //Caution! Z positions (fronts) are off in hcal.param! Correct later on.
348
349 // Fiducial volume limits, based on Plane 1 positions.
350 //
351
352 //NPS base this on array dimensions
353 //Are these only needed if we have tracking detectors in front?
354
355 //Calibration related parameters (from h(s)cal.param).
356
357 DBRequest list[]={
358 {"_cal_min_peds", &fShMinPeds, kInt,0,1},
359 {0}
360 };
361 fShMinPeds=0.;
362
363 gHcParms->LoadParmValues((DBRequest*)&list, fKwPrefix.c_str());
364
365 // Detector axes. Assume no rotation.
366 //
367 DefineAxes(0.);
368
369 fIsInit = true;
370
371 return kOK;
372}
373
374
375//_____________________________________________________________________________
377{
378 // Initialize global variables and lookup table for decoder
379
380 // cout<< "Calling THcNPSCalorimeter::DefineVariables() . . ." << endl;
381
382
383 if( mode == kDefine && fIsSetup ) return kOK;
384 fIsSetup = ( mode == kDefine );
385
386 // Register variables in global list
387
388 RVarDef vars[] = {
389 { "nhits", "(Total) Number of good hits", "fNhits" },
390 { "nclust", "Number of layer clusters", "fNclust" },
391 { "etot", "Total energy", "fEtot" },
392 { "clusX", "Cluster x coordinate", "fClusterX" },
393 { "clusY", "Cluster y coordinate", "fClusterY" },
394 { "clusZ", "Cluster z coordinate", "fClusterZ" },
395 { "clusT", "Cluster time", "fClusterT" },
396 { "clusE", "Cluster energy", "fClusterE" },
397 { "clusSize", "Cluster size", "fClusters.fSize" },
398 { "vtpErrorFlag", "VTP error flag", "fVTPErrorFlag" },
399 { "vtpTrigTime", "VTP trigger time", "fVTPTriggerTime" },
400 { "vtpTrigCrate", "VTP trigger crate", "fVTPTriggerCrate" },
401 { "vtpTrigType0", "VTP trigger cluster singles", "fVTPTriggerType0" },
402 { "vtpTrigType1", "VTP trigger cosmic scin", "fVTPTriggerType1" },
403 { "vtpTrigType2", "VTP trigger cosmic col", "fVTPTriggerType2" },
404 { "vtpTrigType3", "VTP trigger cluster pair different crate", "fVTPTriggerType3" },
405 { "vtpTrigType4", "VTP trigger cluster pair same crate", "fVTPTriggerType4" },
406 { "vtpTrigType5", "VTP trigger VLD", "fVTPTriggerType5" },
407 { "vtpClusTime", "VTP cluster time", "fVTPClusterTime" },
408 { "vtpClusE", "VTP cluster energy", "fVTPClusterEnergy" },
409 { "vtpClusSize", "VTP cluster n blocks", "fVTPClusterSize" },
410 { "vtpClusX", "VTP cluster x coordinate", "fVTPClusterX" },
411 { "vtpClusY", "VTP cluster y coordinate", "fVTPClusterY" },
412 { "vldErrorFlag", "VLD error flag", "fVLDErrorFlag" },
413 { "vldLoChannelMask", "VLD lo channel mask", "fVLDLoChannelMask" },
414 { "vldHiChannelMask", "VLD hi channel mask", "fVLDHiChannelMask" },
415 { "vldColumn", "VLD column", "fVLDColumn" },
416 { "vldRow", "VLD row", "fVLDRow" },
417 { "vldPMT", "VLD PMT", "fVLDPMT" },
418 { 0 }
419 };
420
421 if(fHasArray) {
422
423 RVarDef array_vars[] = {
424
425 //---C.Y. Jan 13, 2021: Commented out for now to avoid replay errors as some of these variable are NOT defined in the header file
426 //(The NPS tracks to match a cluster needs to be given some thought since there is no tracking detector in NPS, so tracks
427 //are simply reconstructed from clusters in NPS calorimeter) : See THcShower.cxx(.h) for info on use of these variables
428 //{ "sizeclustarray", "Number of block in array cluster that matches track", "fSizeClustArray" },
429 //{ "nclustarraytrack", "Number of cluster for Fly's eye which matched best track","fNclustArrayTrack" },
430 //{ "nblock_high_ene", "Block number in array with highest energy which matched best track","fNblockHighEnergy" },
431 //{ "xclustarraytrack", "X pos of cluster which matched best track","fXclustArrayTrack" },
432 //{ "xtrackarray", "X pos of track which matched cluster", "fXTrackArray" },
433 //{ "yclustarraytrack", "Y pos of cluster which matched best track","fYclustArrayTrack" },
434 //{ "ytrackarray", "Y pos of track which matched cluster", "fYTrackArray" },
435 { 0 }
436 };
437
438 DefineVarsFromList( array_vars, mode );
439 }
440 return DefineVarsFromList( vars, mode );
441
442}
443
444//_____________________________________________________________________________
446{
447 // Destructor. Remove variables from global list.
448 // cout<< "Calling Destructor | THcNPSCalorimeter::~THcNPSCalorimeter() . . ." << endl;
449
450 Clear();
451 if( fIsSetup )
453 if( fIsInit )
454 DeleteArrays();
455
456 for (THcNPSShowerClusterListIt i=fClusterList->begin(); i!=fClusterList->end();
457 ++i) {
458 Podd::DeleteContainer(**i);
459 delete *i;
460 }
461 delete fClusterList; fClusterList = 0;
462 delete fArray; fArray = 0;
463
464 //close output file
465 if(fMakeGrid){
466 fOutFile->close();
467 }
468
469}
470
471//_____________________________________________________________________________
473{
474 // Delete member arrays. Used by destructor.
475
476 for (UInt_t i = 0; i<fNTotLayers; ++i)
477 delete [] fLayerNames[i];
478 delete [] fLayerNames; fLayerNames = 0;
479
480}
481
482//_____________________________________________________________________________
483inline
485{
486
487// Reset per-event data.
488
489 if(fHasArray) {
490 fArray->Clear(opt);
491 }
492
493 fNhits = 0;
494 fNclust = 0;
495 fEtot = 0.;
496 fEtotNorm = 0.;
497 fEtrack = 0.;
498 fEtrackNorm = 0.;
499 fEPRtrack = 0.;
500 fEPRtrackNorm = 0.;
501 fETotTrackNorm = 0.;
503
504 // Purge cluster list
505 for (THcNPSShowerClusterListIt i=fClusterList->begin(); i!=fClusterList->end();
506 ++i) {
507 Podd::DeleteContainer(**i);
508 delete *i;
509 }
510 fClusterList->clear();
511
512 fClusters.clear();
513
514 fClusterX.clear();
515 fClusterY.clear();
516 fClusterZ.clear();
517 fClusterT.clear();
518 fClusterE.clear();
519
520 fVLDLoChannelMask.clear();
521 fVLDHiChannelMask.clear();
522 fVLDColumn.clear();
523 fVLDRow.clear();
524 fVLDPMT.clear();
525
526}
527
528//_____________________________________________________________________________
530{
531
532 //cout << "--------------------> New Event Number: " << evdata.GetEvNum() << endl;
533 Bool_t clear = false;
534
535 // DJH 09/04/22 -- only create dedicated analyzer object if using SHMS data
536 if(fCalReplicate==0)
538
539 if(clear) Clear();
540 // Should move this up to the apparatus level.
541
542 // DJH: decode VTP and VLD here (for now)
543 // cout << " event = " << evdata.GetEvNum() << endl;
544 Int_t Nvtpfound = 0;
545 Int_t Nvldfound = 0;
546 fVTPTriggerTime.clear();
547 fVTPTriggerCrate.clear();
548 fVTPTriggerType0.clear();
549 fVTPTriggerType1.clear();
550 fVTPTriggerType2.clear();
551 fVTPTriggerType3.clear();
552 fVTPTriggerType4.clear();
553 fVTPTriggerType5.clear();
554 for (UInt_t i=0; i < fDetMap->GetSize(); i++) {
555
557
558 Decoder::VTPModule* isvtp = dynamic_cast<Decoder::VTPModule*>(evdata.GetModule(d->crate, d->slot)); // Look for a VTP
559 if(isvtp) {
560 Nvtpfound++;
561 Int_t crate_num= d->crate;
562 if( evdata.GetEvNum() != isvtp->GetTriggerNum() ) {
563 // cout << "THcNPSCalorimeter VTP data synch error: THaEvData = " << evdata.GetEvNum() << ", VTP decoder = "<< isvtp->GetTriggerNum() << " for VTP in crate" << d->crate << endl;
564 fVTPErrorFlag = 1;
565 }
566 else {
567 //cout << " vtp crate = " << d->crate << " slot = " << d->slot << endl;
568 // cout << " vtp found = " << Nvtpfound << endl;
569 if( Nvtpfound == 1 ) {
571 for ( UInt_t nn=0 ; nn < fVTPTriggerTime.size(); nn++) {
572 fVTPTriggerCrate.push_back(crate_num);
573 }
580 // cout << " fVTPTriggerType0 = " << fVTPTriggerType0[0]<< " fVTPTriggerType1 = " << fVTPTriggerType1[0]<< " fVTPTriggerType2 = " << fVTPTriggerType2[0]<< " fVTPTriggerType3 = " << fVTPTriggerType3[0]<< " fVTPTriggerType4 = " << fVTPTriggerType4[0] << " fVTPTriggerType5 = " << fVTPTriggerType5[0] << endl;
581
585 fVTPClusterX = isvtp->GetClusterX();
586 fVTPClusterY = isvtp->GetClusterY();
587 }
588 else {
589 /* Triggertype#
590 0 - production singles
591 1 - cosmic scintillator
592 2 - cosmic column
593 3 - pair threshold (1 cluster in crate)
594 4 - pair threshold (2 cluster in same crate)
595 5 - vld
596 */
597 auto temp1 = isvtp->GetTriggerTime();
598 fVTPTriggerTime.insert( fVTPTriggerTime.end(), temp1.begin(), temp1.end() );
599 for ( UInt_t nn=0 ; nn < temp1.size(); nn++) {
600 fVTPTriggerCrate.push_back(crate_num);
601 }
602 auto temp2 = isvtp->GetTriggerType0();
603 fVTPTriggerType0.insert( fVTPTriggerType0.end(), temp2.begin(), temp2.end() );
604 auto temp3 = isvtp->GetTriggerType1();
605 fVTPTriggerType1.insert( fVTPTriggerType1.end(), temp3.begin(), temp3.end() );
606 auto temp4 = isvtp->GetTriggerType2();
607 fVTPTriggerType2.insert( fVTPTriggerType2.end(), temp4.begin(), temp4.end() );
608 auto temp44= isvtp->GetTriggerType3();
609 fVTPTriggerType3.insert( fVTPTriggerType3.end(), temp44.begin(), temp44.end() );
610 auto temp45= isvtp->GetTriggerType4();
611 fVTPTriggerType4.insert( fVTPTriggerType4.end(), temp45.begin(), temp45.end() );
612 auto temp46= isvtp->GetTriggerType5();
613 fVTPTriggerType5.insert( fVTPTriggerType5.end(), temp46.begin(), temp46.end() );
614 auto temp5 = isvtp->GetClusterTime();
615 fVTPClusterTime.insert( fVTPClusterTime.end(), temp5.begin(), temp5.end() );
616 auto temp6 = isvtp->GetClusterEnergy();
617 fVTPClusterEnergy.insert( fVTPClusterEnergy.end(), temp6.begin(), temp6.end() );
618 auto temp7 = isvtp->GetClusterSize();
619 fVTPClusterSize.insert( fVTPClusterSize.end(), temp7.begin(), temp7.end() );
620 auto temp8 = isvtp->GetClusterX();
621 fVTPClusterX.insert( fVTPClusterX.end(), temp8.begin(), temp8.end() );
622 auto temp9 = isvtp->GetClusterY();
623 fVTPClusterY.insert( fVTPClusterY.end(), temp9.begin(), temp9.end() );
624
625 }
626 /*
627 cout << " size = " << fVTPTriggerTime.size() << endl;
628 for ( Int_t nn=0;nn<fVTPTriggerTime.size();nn++) {
629 cout << " nn = " << nn << "FVTPtriggerType0 = " << fVTPTriggerType0[nn] << " VTPTriggerType1 = " << fVTPTriggerType1[nn]<< " fVTPTriggerType2 = " << fVTPTriggerType2[nn]<< " fVTPTriggerType3 = " << fVTPTriggerType3[nn]<< " fVTPTriggerType4 = " << fVTPTriggerType4[nn] << " fVTPTriggerType5 = " << fVTPTriggerType5[nn] << endl;
630 }
631 */
632 }
633 }
634
635 Decoder::VLDModule* isvld = dynamic_cast<Decoder::VLDModule*>(evdata.GetModule(d->crate, d->slot)); // Look for a VLD
636
637 if(isvld) {
638
639 Nvldfound++;
640
641 auto vldChannelMask = isvld->GetChannelMask();
642 auto vldLoHiBit = isvld->GetLoHiBit();
643 auto vldConnectorID = isvld->GetConnectorID();
644
645 UInt_t column, pmt;
646
647 for(size_t i=0; i<vldChannelMask.size(); i++ ) {
648
649 if( vldChannelMask.at(i) == 0 ) continue;
650
651 if( Nvldfound == 1 )
652 column = vldConnectorID.at(i) + 27 ;
653 else if( Nvldfound == 2 )
654 column = vldConnectorID.at(i) + 24 ;
655 else if( Nvldfound >= 3 && Nvldfound <= 10 )
656 column = vldConnectorID.at(i) + (3 * i/8);
657 else{
658 cout << "THcNPSCalorimeter VLD decode error: Found " << Nvldfound << " VLD modules. There should be " << fnVLD << endl;
659 fVLDErrorFlag = 1;
660 }
661
662 if( Nvldfound > 3 ) continue;
663
664 for( int row=0; row<18; row++) {
665
666 if( TESTBIT(vldChannelMask.at(i), row) ) {
667
668 if( vldLoHiBit.at(i) == 0 ) {
669 fVLDLoChannelMask.push_back( vldChannelMask.at(i) );
670 fVLDRow.push_back( row );
671 fVLDPMT.push_back( column + (30*row) );
672 fVLDColumn.push_back( column );
673 }
674
675 if( vldLoHiBit.at(i) == 1 ) {
676 fVLDHiChannelMask.push_back( vldChannelMask.at(i) );
677 fVLDRow.push_back( (row + 18) );
678 fVLDPMT.push_back( column + (30*(row+18)) );
679 fVLDColumn.push_back( column );
680 }
681
682 }
683 }
684 }
685 }
686
687 }
688
689 if( Nvtpfound > fnVTP ) {
690 cout << "THcNPSCalorimeter VTP decode error: Found " << Nvtpfound << " VTP modules. There should be " << fnVTP << endl;
691 fVTPErrorFlag = 1;
692 }
693
694 // Get the Hall C style hitlist (fRawHitList) for this event
695 Bool_t present = kTRUE; // Suppress reference time warnings
696 if(fPresentP) { // if this spectrometer not part of trigger
697 present = *fPresentP;
698 }
699 Int_t nhits = DecodeToHitList(evdata, !present);
700
701 //cout<< "total number of blocks hit = " << nhits << endl;
702 fEvent = evdata.GetEvNum();
703
704 if(gHaCuts->Result("Pedestal_event")) {
705 Int_t nexthit = 0;
706 if(fHasArray) {
707 nexthit = fArray->AccumulatePedestals(fRawHitList, nexthit);
708 }
709 fAnalyzePedestals = 1; // Analyze pedestals first normal events
710 return(0);
711 }
712
714 if(fHasArray) {
716 }
717 fAnalyzePedestals = 0; // Don't analyze pedestals next event
718 }
719
720 Int_t nexthit = 0;
721 if(fHasArray) {
723 quadrant = -1;
724 if(fCalReplicate>0) {
725 quadrant = gRandom->Integer(4) + (fCalReplicate>1?4:0);
726 }
727 // cout<< "----> quadrant = " << quadrant << endl;
728 nexthit = fArray->AccumulateHits(fRawHitList, nexthit, quadrant);
729 }
730 // cout << "Nhits=" << nhits << endl;
731 return nhits;
732
733 // return 0;
734}
735
736//_____________________________________________________________________________
738{
739
740 // cout<< "Calling THcNPSCalorimeter::CoarseProcess() . . . " << endl;
741
742 // Calculation of coordinates of particle track cross point with shower
743 // plane in the detector coordinate system. For this, parameters of track
744 // reconstructed in THaVDC::CoarseTrack() are used.
745 //
746 // Apply corrections and reconstruct the complete hits.
747
748 // Clustering of hits.
749 //
750
751 // Fill set of unclustered hits.
752 if(fHasArray) {
754 //C.Y. Feb 07 2021: I think there should NOT be a +=, since fArray->GetEarray() already returns the total deposited energy
755 //for some reason, fEtot is slighly different from fArray in the ROOTfile, where they should actually be exactly the same
756 fEtot += fArray->GetEarray();
757 }
758 //THcHallCSpectrometer *app = static_cast<THcHallCSpectrometer*>(GetApparatus());
759 // fEtotNorm=fEtot/(app->GetPcentral());
760 fEtotNorm = 1.0;
761 //
762
763 // Do same for Array.
764
765 //C.Y. Feb 07 2021: The tracks input on this method is irrelevant as NPS doe NOT use tracks (should eventually be taken out)
767
768 //
769 return 0;
770}
771
772//-----------------------------------------------------------------------------
773
775 THcNPSShowerClusterList* ClusterList) {
776
777 //cout<< "Calling THcNPSCalorimeter::ClusterHits() . . . " << endl;
778
779 // Collect hits from the HitSet into the clusters. The resultant clusters
780 // of hits are saved in the ClusterList.
781
782 //cout << "HitSet Size = " << HitSet.size() << endl;
783 fNhits = HitSet.size();
784
785 while (HitSet.size() != 0) {
786
788
789 THcNPSShowerHitIt it = HitSet.end();
790 (*cluster).insert(*(--it)); //Move the last hit from the hit list
791 HitSet.erase(it); //into the 1st cluster
792
793 bool clustered = true;
794
795 while (clustered) { //Proceed while a hit is clustered
796
797 clustered = false;
798
799 for (THcNPSShowerHitIt i=HitSet.begin(); i!=HitSet.end(); ++i) {
800
801 for (THcNPSShowerClusterIt k=(*cluster).begin(); k!=(*cluster).end();
802 ++k) {
803
804 if ((**i).isNeighbour(*k)) {
805 (*cluster).insert(*i); //If the hit #i is neighbouring a hit
806 HitSet.erase(i); //in the cluster, then move it
807 //into the cluster.
808 clustered = true;
809 }
810
811 if (clustered) break;
812 } //k
813
814 if (clustered) break;
815 } //i
816
817 } //while clustered
818
819 ClusterList->push_back(cluster); //Put the cluster in the cluster list
820
821 } //While hit_list not exhausted
822
823
824 fNclust = (*ClusterList).size();
825
826 // Add clusters
827 for (THcNPSShowerClusterListIt ppcl = (*ClusterList).begin();
828 ppcl != (*ClusterList).end(); ++ppcl) {
829 THcNPSCluster cls(clX(*ppcl), clY(*ppcl), clZ(*ppcl), clT(*ppcl), clE(*ppcl));
830
831 // Add block IDs for the cluster
832 for(THcNPSShowerClusterIt pph=(*ppcl)->begin(); pph!=(*ppcl)->end(); ++pph) {
833 cls.AddBlock( (*pph)->hitID() );
834 }
835
836 fClusters.push_back(cls);
837
838 fClusterX.push_back(cls.X());
839 fClusterY.push_back(cls.Y());
840 fClusterZ.push_back(cls.Z());
841 fClusterT.push_back(cls.T());
842 fClusterE.push_back(cls.E());
843 }
844
845 // C.Y. Apr 07, 2021: Added lines to write clusters to file for plotting in 2D grid (and comparing to NPS clustering approach)
846 if(fMakeGrid) {
847
848 //cout << "ClusterList Size = " << ClusterList->size() << endl;
849
850 //Loop over ALL clusters per event
851 for (size_t i=0; i<ClusterList->size(); i++){
852
853 //Loop over ALL hit blocks per cluster per event
854 for(THcNPSShowerClusterIt j=(*ClusterList->at(i)).begin(); j!=(*ClusterList->at(i)).end(); ++j){
855
856 *fOutFile << "\t" << fEvent << ",\t\t\t" << ClusterList->size() << ",\t\t\t" << (i+1) << ",\t\t\t" << (*j)->hitID() << ",\t\t\t" << (*j)->hitT() << ",\t\t\t" << (*j)->hitPI() << ",\t\t\t" << (*j)->hitE() <<endl;
857
858
859 } //end loop over hit blocks per cluster
860
861 } //end loop over clusters
862
863 } //end fMakeGrid requirement
864
865};
866
867//-----------------------------------------------------------------------------
868
869
870
871//-----------------------------------------------------------------------------
873
874 /*
875 C.Y. Feb 09, 2021
876 Brief: This method does the Neutral Particle Spectrometer (NPS) clustering following
877 the Cellular Automata approach (https://inis.iaea.org/collection/NCLCollectionStore/_Public/29/006/29006611.pdf?r=1&r=1).
878 In addition, as was done in Hall A DVCS, 3D clustering is done by selecting block adc
879 pulse hits that fall within a certain adc pulse time window (timemin, timemax) and raw pulse integral that pass a threshold
880
881 C.Y. Feb 21, 2021
882 ** TO-DO NOTE ** : Currently, to select the best possible hit (if a block has multiple adc hits per event) is to loop over all raw
883 hits per block, and select the hit that is closest to the adc pulse time average (timemin+timemax)/2. The issue is that the loop
884 over raw hits is already done in AccumulateHits(), and it is best practive NOT to repeat the same loop (memory efficiency). Eventually,
885 it is best to determine the best adc hit per block within the AccumulateHits() method itself, and pass that information to this method.
886 In addition, the selection of the best hit in a block must also be thought more carefully, as the following scenario is possible:
887 "Imagine a cluster of hits on blocks 2, 3 and 4, all at 20 ns. Then another cluster of hits with blocks 4, 5 and 6, all at 40 ns.
888 We want to make sure that both hits on block 4 are used. " --S.A. Wood
889
890 **NOTE 2: Recall, for NPS, the fADC Dynamic Range (variable name: fAdcRange) will be set to 2 V. Currently, in THcRawAdcHit.cxx(.h),
891 a dynamic range of 1 V is used (for HMS/SHMS fADC). Will need to add an option for 2V if analyzing NPS.
892
893 C.Y. Mar 28, 2021
894 How is the set of pulse Integral hits (fNPSPulseInt) constructed?
895 The fNPSPulseInt is a vector of total number of blocks, where each block, contains a vector of hits for that particular block per event.
896 This vector of vectors variable is filled in the THcNPSArray.cxx class under the THcNPSArray::FillADC_DynamicPedestal()
897 method, given that certain conditions are fulfilled (i.e., errorflag==0, hit is within adctdcdiffTime window, and good
898 adc pulse integral raw is above threshold).
899
900
901 C.Y. Apr 04, 2021 : Event 987 of Run 10398 is a good event to check code,as it only has a single cluster of 4 hits
902 and can be used to understand how the algorithm contaminates other blocks based on a central virus block.
903 */
904
905 fNhits = HitSet.size();
906
907 //********************************************
908 // PHASE 1 PREP: ARRAY/VECTORS INITIALIZATION
909 //********************************************
910
911 //total number of blocks
913 Int_t fNbBlocks = 0; //counter of number of blocks hit
914
915 //Define vectors to store hit blocks info
916 vector<Double_t> blk_pulseInt(fNelem, -1); //store max pulse integral for ALL blocks (by default, is -1 for all elements)
917 vector<Double_t> blk_pulseTime(fNelem, -1); //store pulse time of largest pulse for ALL blocks (by default, is -1 for all elements)
918 vector<Int_t> good_blk_id; //store block id that was hit (variable-size), specifies (index hit, block_id hit)
919 vector<Double_t> good_blk_pulseInt; //store max pulse integral per block hit (if there are multiple hits) (index hit, max pulse Int)
920
921 //clusters counter
922 Int_t NbClusters=0;
923
924 //Hit Block indexing (e.g, for a given event, if hit blocks are: 34, 65, 78, then corresponding indices are: = 0, 1, 2)
925 Int_t blk_hit_idx[fNelem];
926
927 //initialize arrays
928 for(int ielem=0; ielem<fNelem; ielem++){
929 blk_hit_idx[ielem]=-1;
930 }
931
932 //---------TESTING: ASSIGN PULSE INT USING HIT SET-------
933 //Loop over ALL Hit blocks
934 for (THcNPSShowerHitIt ihit=HitSet.begin(); ihit!=HitSet.end(); ++ihit) {
935
936 // fill vectors
937 // Use energy instead of integral for clustering 10/09/2023 S.P
938 blk_pulseInt[ (*ihit)->hitID() ] = (*ihit)->hitE();
939 blk_pulseTime[ (*ihit)->hitID() ] = (*ihit)->hitT();
940 good_blk_id.push_back( (*ihit)->hitID() );
941 good_blk_pulseInt.push_back( (*ihit)->hitE() );
942
943 //Set hit block index
944 blk_hit_idx[ (*ihit)->hitID() ] = fNbBlocks;
945
946 //increment hit block counter
947 fNbBlocks++;
948
949 }
950
951 //Boolean arrays to "tag" blocks of interest as viruses when forming clusters
952 Bool_t virus[fNbBlocks], virustmp[fNbBlocks], ill[fNbBlocks];
953
954 //********************************
955 // PHASE 1: VIRUS IDENTIFICATION
956 //********************************
957
958 //Loop over ONLY NPS blocks that have a good hit to identify which of the blocks hit
959 //are a local maxima (known as the virus in cellular automata method, and have the
960 //highest pulse signal compared to its nearest neighbors)
961 // cout << "" << endl;
962 // cout << "********************************\n"
963 // "PHASE 1: VIRUS IDENTIFICATION\n"
964 // "********************************" << endl;
965
966 for(Int_t j=0; j < fNbBlocks; j++){
967
968 //cout << "--------CENTRAL J-th Block------ " << endl;
969 //cout << "(j-index, Block ID, pulseInt) = " << j << ", " << good_blk_id[j] << ", " << good_blk_pulseInt[j] << endl;
970 //cout << "-------------------------------- " << endl;
971 //By default, each j-th block that has a good hit is hit is considered a
972 //virus (highest pulse integral compared to nearest neighbors)
973 ill[j] = false;
974 virus[j] = true;
975 virustmp[j]= true;
976
977 //For each good 'j-th' block hit, Loop over each of the (at most) 8 neighboring blocks (or cells)
978 //If at a corner (only 3 neighboring blocks) and if at an edge (only 5 neighboring blocks)
979 for(Int_t k=0;k<8;k++){
980
981 //cout<< "(k-index, Neighbor Block ID) = " << k << ", " << fArray->GetNeighbor(good_blk_id[j], k) << endl;
982
983 //Check if kth neighbor block exists (is physically real) and was actually hit
984 //if( fArray->GetNeighbor(good_blk_id[j], k)!=-1 && blk_pulseInt[ fArray->GetNeighbor(good_blk_id[j], k) ]>0 ){
985 if( fArray->GetNeighbor(good_blk_id[j], k)!=-1 && blk_hit_idx[ fArray->GetNeighbor(good_blk_id[j], k) ]!=-1 ) {
986
987 // cout<< "Valid Neighbor Found : (k-index, Neighbor Block ID, pulseInt) = " << k << ", " << fArray->GetNeighbor(good_blk_id[j], k) << ", " << blk_pulseInt[ fArray->GetNeighbor(good_blk_id[j], k) ] << endl;
988
989 //Check if the kth neighbor block good pulse integral is greater than the ith central block (if so, then the central block is NOT a virus)
990 //if( blk_pulseInt[ fArray->GetNeighbor(good_blk_id[j], k) ] > blk_pulseInt[ good_blk_id[j] ] ){
991 if( blk_pulseInt[ fArray->GetNeighbor(good_blk_id[j], k) ] > good_blk_pulseInt[j] ){
992 //cout<< " k-th Neighbor Pulse Integral > j-th Central Block Pulse Integral | Set 'virus[j]=false' for central block !" << endl;
993 //set to false if ith central block is NOT a virus (If there's one neighbour with more energy, it's not a local maximum)
994 virus[j] = false;
995 virustmp[j]= false;
996 }
997
998 }
999
1000 }//end loop over k neighbors
1001
1002 //If none of the k neighbors pulse integral is greater than the central block, then
1003 //the central block will remain a virus (true) and the number of clusters is incremented
1004 if (virus[j]==true) { NbClusters++; }
1005
1006 }//end loop over hit fNbBlocks
1007
1008
1009 //********************************************
1010 // PHASE 2 PREP: ARRAY/VECTORS INITIALIZATION
1011 //********************************************
1012
1013
1014 //Float arrays to pulse integrals during the "contamination phase" of the algorithm
1015 Float_t pIpas[fNelem], pIpastmp[fNelem], pInei[8];
1016
1017 //pulseInt Array of number of viruses (NbClusters) identified above
1018 Float_t pIvirus[NbClusters];
1019 Int_t cp = 0; //virus counter
1020
1021 //cout << "-------------------" << endl;
1022 //cout << "Check Virus Blocks " << endl;
1023 //cout << "-------------------" << endl;
1024 //Loop over all blocks that have adc hit and check if they are a virus.
1025 //If they are a virus, assign the corresponding pulseInt to pIvirus
1026 for(Int_t j=0; j<fNbBlocks; j++){
1027
1028 //check if 'jth' hit block is a virus
1029 if(virus[j]==true){
1030 //cout << "(Virus Block ID, Pulse Int) = " << good_blk_id[j] << ", " << good_blk_pulseInt[j] << endl;
1031 pIvirus[cp] = good_blk_pulseInt[j]; //Virus' energies
1032 cp++;
1033
1034 }
1035 }
1036
1037 //Loop over ALL calorimeter blocks to initialize pulse Int arrays to be used in contamination phase
1038 for(Int_t ielem = 0; ielem < fNelem; ielem++){
1039
1040 //assign initial values to arrays
1041 pIpas[ielem] = 0.;
1042 pIpastmp[ielem] =-1.;
1043 }
1044
1045
1046 //Loop over all blocks that had a hit
1047 for(Int_t j=0; j<fNbBlocks; j++){
1048
1049 //assign pulse integral to pIpas
1050 pIpas[ good_blk_id[j] ] = good_blk_pulseInt[j];
1051
1052 //If the 'jth' block was identified as a virus previously, then set ill[j] = true, and assign a temporary pulseInt pIpastmp
1053 //corresponding to the virus pulse integral. The virus block will be identified as already ill in the contamination phase.
1054 if(virus[j]) {
1055
1056 ill[j] = true;
1057 pIpastmp[ good_blk_id[j] ] = good_blk_pulseInt[j];
1058
1059 }
1060 }
1061
1062 //********************************
1063 // PHASE 2: VIRUS CONTAMINATION
1064 //********************************
1065
1066 //cout << "" << endl;
1067 //cout << "********************************\n"
1068 // "PHASE 2: VIRUS CONTAMINATION\n"
1069 // "********************************" << endl;
1070
1071
1072 //Contamination: Now that the virus cells are identified, its neighbouring cells must
1073 //now be contaminated (i.e., become ill), and must somehow be tagged with the virus cell
1074 //until all cells contaminated by a virus become ill
1075
1076
1077 //Set starting values for the iterative contamination
1078 Int_t safe=0, nbfine=1, virus_blk=-2;
1079
1080 //Initialize iterations, with an upper limit of 15 iterations
1081 while(nbfine>0 && safe<15){
1082
1083 //increment safe iterator
1084 safe++;
1085
1086 //cout << "---> Begin Safe Iteration Number = " << safe << endl;
1087 //Loop over blocks that have a hit
1088 for(Int_t j=0; j<fNbBlocks; j++){
1089
1090 //cout << "(j-th index, Block ID Hit, virus?, ill? ) = " << j << ", " << good_blk_id[j] << ", " << virus[j] << ", " << ill[j] << endl;
1091 //----BEGIN 'ILL BLOCK' CHECK-----
1092
1093 /*Check if block has been contaminated (ill). The virus blocks have
1094 already been set to ill=true previously. The neighboring blocks,
1095 however, have not yet been determined to be ill, so they must be
1096 identified and contaminated*/
1097
1098 if(!ill[j]){ //if hit block has not been contaminated (i.e., not a virus and therefore, not ill) . . .
1099
1100 //cout << "NON-ILL BLOCK FOUND | j-th index, Non-Ill Block ID = " << j << ", " << good_blk_id[j] << endl;
1101 //variables to store pulse int and block id of neighbor with higher pulseInt
1102 Float_t max=0.;
1103 Int_t nei[8];
1104
1105 //Loop over (at most 8) neighboring blocks
1106 for(Int_t k=0; k<8; k++){
1107
1108 //cout<< "(k-index, Neighbor Block ID) = " << k << ", " << fArray->GetNeighbor(good_blk_id[j], k) << endl;
1109
1110 //Check if kth neighbor block exists (is physically real) and was actually hit within clustering time window (has good pulse integral in time window)
1111 //M. Mathison Oct. 31, 2023: Added in time window for clustering.
1112 if( fArray->GetNeighbor(good_blk_id[j], k)!=-1 && blk_hit_idx[ fArray->GetNeighbor(good_blk_id[j], k) ]!=-1 && (blk_pulseTime[ fArray->GetNeighbor(good_blk_id[j], k) ] - blk_pulseTime[ good_blk_id[j] ]) > -fClusterTimeWindow && (blk_pulseTime[ fArray->GetNeighbor(good_blk_id[j], k) ] - blk_pulseTime[ good_blk_id[j] ]) < fClusterTimeWindow ){
1113
1114 //cout<< "Valid Neighbor Found : (k-index, Neighbor Block ID, pulseInt) = " << k << ", " << fArray->GetNeighbor(good_blk_id[j], k) << ", " << blk_pulseInt[ fArray->GetNeighbor(good_blk_id[j], k) ] << endl;
1115
1116 //Set pulseInt of kth neighbour block
1117 pInei[k] = pIpas[ fArray->GetNeighbor(good_blk_id[j], k) ];
1118 }
1119 //If kth neighbor does not exist or has no hit, set to zero
1120 else{
1121 pInei[k] = 0.;
1122 }
1123
1124 //--------
1125
1126 //Check if kth neighbor block exists (is physically real)
1127 if( fArray->GetNeighbor(good_blk_id[j], k)!=-1 ){
1128 //assign a hit index for the 'kth' the neighbor of the 'jth' block
1129 nei[k] = blk_hit_idx[ fArray->GetNeighbor(good_blk_id[j], k) ];
1130 }
1131 else{
1132 nei[k] = -1;
1133 }
1134
1135 }//end loop over (at most 8) neighboring blocks
1136
1137 //get the highest neighboring cell block hit index (virus_blk) and corresponding pulseInt (max)
1138 fArray->GetMax(pInei, nei, virus_blk, max);
1139 //Set temporaty pulse Int container to the highest pulse Int of the neighbor block.
1140 //Here is where the j-th hit block (that was not ill) is tagged' with the neighboring block highest pulseInt
1141 pIpastmp[ good_blk_id[j] ]=max;
1142
1143 //cout << "Neighbor w/ Highest Pulse Int | (Block Hit Index, PulseInt) = " << good_blk_id[j] << " " << virus_blk << ", " << max << endl;
1144 //Check if the found neighboring block (virus_blk) with the highest pulse Integral has been previously tagged as a virus
1145 if(virus[virus_blk]){
1146
1147 //cout << "Neighbor w/ Highest Pulse Int is a VIRUS ! ! ! " << endl;
1148 //cout << "Set j-th block index and virustmp[j] to TRUE (Contaminate j-th block) | (j-th index, Block ID) = " << j << ", " << good_blk_id[j] << endl;
1149
1150 //If the neighboring 'kth' block has been tagged as a virus, then the central 'jth' block will become ill (contaminated) with the virus
1151 ill[j] = true;
1152 virustmp[j] = true;
1153
1154 }
1155
1156 }//end (!ill[j] check)
1157
1158
1159 //----END 'ILL BLOCK' CHECK-----
1160
1161 } //end loop over hit blocks (fNbBlocks)
1162
1163 //Update arrays before the next iteration, after looping over all hits blocks (fNbBlocks)
1164 for(Int_t i=0; i<fNelem; i++){
1165
1166 //Update virus flag of the ith hit index (note in this context, i is a hit index, not a block number)
1167 if(i<fNbBlocks) { virus[i] = virustmp[i]; }
1168
1169 //check if ith element has a hit (pulseInt!=-1)
1170 if(pIpastmp[i]!=-1){
1171 //assign pulse Int array the updated pulse Int for the ith block id
1172 pIpas[i]=pIpastmp[i];
1173 }
1174
1175 }
1176
1177 //Test for still ill blocks. Otherwise iteration is complete !
1178 nbfine=0; //set to zero (no next iteration) unless proven otherwise
1179
1180 for(Int_t i=0; i<fNbBlocks; i++){
1181
1182 //If the ith hit index block is not ill, then iterative process must continue untill all blocks are ill (contaminated)
1183 //or an upper safety limit is reached
1184
1185 if(!ill[i]) {
1186 nbfine++; //increment nbfine (so that nbfine>0 to do next iteration)
1187 }
1188
1189 }
1190
1191 }//end iterative loop
1192
1193
1194 //***********************************************************
1195 //
1196 // ADD CLUSTERS (CORRELATED GROUP OF HIT BLOCKS) TO A LIST
1197 //
1198 //***********************************************************
1199
1200 //Check if HitSet (containing hit objects of blocks that were hit)
1201 while (HitSet.size() != 0) {
1202
1203 //initialize a set called 'cluster' to stored clustered hits
1205
1206
1207 THcNPSShowerHitIt it = HitSet.end(); //Get last hit in the set
1208 (*cluster).insert(*(--it)); //Move the last hit from the hit set into the 1st cluster (as starting point)
1209 HitSet.erase(it); //Erase the hit from the HitSet (to keep track) of which hits have been added to cluster
1210
1211 bool clustered = true;
1212
1213 while (clustered) { //Proceed while a hit is clustered
1214
1215 clustered = false;
1216
1217 //Iterate over unclustered set of hits
1218 for (THcNPSShowerHitIt i=HitSet.begin(); i!=HitSet.end(); ++i) {
1219
1220 //Iterate over clustered set
1221 for (THcNPSShowerClusterIt k=(*cluster).begin(); k!=(*cluster).end();
1222 ++k) {
1223
1224 //cout << "TESTING 1: (*i)->hitID = " << (*i)->hitID() << ", (*i) PI = " << pIpas[ (*i)->hitID() ] << ", (*i) T = " << blk_pulseTime[ (*i)->hitID() ] << endl;
1225 //cout << "TESTING 2: (*k)->hitID = " << (*k)->hitID() << ", (*k) PI = " << pIpas[ (*k)->hitID() ] << ", (*k) T = " << blk_pulseTime[ (*k)->hitID() ] << endl;
1226 //cout << "TESTING 3: Pulse diff T = " << blk_pulseTime[ (*i)->hitID() ] - blk_pulseTime[ (*k)->hitID() ] << endl;
1227 if(pIpas[ (*i)->hitID() ] == pIpas[ (*k)->hitID() ] && (blk_pulseTime[ (*i)->hitID() ] - blk_pulseTime[ (*k)->hitID() ]) > -fClusterTimeWindow && (blk_pulseTime[ (*i)->hitID() ] - blk_pulseTime[ (*k)->hitID() ]) < fClusterTimeWindow){
1228 // if ((**i).isNeighbour(*k)) {
1229 (*cluster).insert(*i); //If the hit #i is neighbouring a hit
1230 HitSet.erase(i); //in the cluster, and the hits are
1231 //within the time window,
1232 clustered = true; //then move it into the cluster.
1233 //cout << "Clustered!" << endl;
1234 }
1235
1236 //else cout << "NOT clustered!" << endl;
1237
1238 if (clustered) break;
1239 } //k
1240
1241 if (clustered) break;
1242 } //i
1243
1244 } //while clustered
1245
1246 ClusterList->push_back(cluster); //Put the cluster in the cluster list
1247
1248 }
1249
1250 fNclust = (*ClusterList).size();
1251
1252 for (THcNPSShowerClusterListIt ppcl = (*ClusterList).begin();
1253 ppcl != (*ClusterList).end(); ++ppcl) {
1254 THcNPSCluster cls(clX(*ppcl), clY(*ppcl), clZ(*ppcl), clT(*ppcl), clE(*ppcl));
1255
1256 // Add block IDs for the cluster
1257 for(THcNPSShowerClusterIt pph=(*ppcl)->begin(); pph!=(*ppcl)->end(); ++pph) {
1258 cls.AddBlock( (*pph)->hitID() );
1259 }
1260
1261 fClusters.push_back(cls);
1262
1263 fClusterX.push_back(cls.X());
1264 fClusterY.push_back(cls.Y());
1265 fClusterZ.push_back(cls.Z());
1266 fClusterT.push_back(cls.T());
1267 fClusterE.push_back(cls.E());
1268 }
1269
1270 // C.Y. Apr 07, 2021: Added lines to write clusters to file for plotting in 2D grid (and comparing to NPS clustering approach)
1271 if(fMakeGrid) {
1272
1273 //cout << "fEvent = " << fEvent << endl;
1274 //cout << "ClusterList Size = " << ClusterList->size() << endl;
1275
1276 //Loop over ALL clusters per event
1277 for (size_t i=0; i<ClusterList->size(); i++){
1278
1279 //cout << "----> Cluster i = " << i << endl;
1280 //cout << "# of hits in cluster = " << (*ClusterList->at(i)).size() << endl;
1281
1282 //Loop over ALL hit blocks per cluster per event
1283 for(THcNPSShowerClusterIt j=(*ClusterList->at(i)).begin(); j!=(*ClusterList->at(i)).end(); ++j){
1284
1285 //cout << "blockID = " << (*j)->hitID() << endl;
1286 //cout << "blockE = " << (*j)->hitE() << endl;
1287 //cout << "blockT = " << (*j)->hitT() << endl;
1288
1289 *fOutFile << "\t" << fEvent << ",\t\t\t" << ClusterList->size() << ",\t\t\t" << (i+1) << ",\t\t\t" << (*j)->hitID() << ",\t\t\t" << (*j)->hitT() << ",\t\t\t" << (*j)->hitPI() << ",\t\t\t" << (*j)->hitE() << endl;
1290
1291
1292 } //end loop over hit blocks per cluster
1293
1294 } //end loop over clusters
1295
1296 } //end fMakeGrid requirement
1297
1298
1299}
1300//-----------------------------------------------------------------------------
1301
1302
1303
1304
1305// Various helper functions to accumulate hit related quantities.
1306
1308 return x + h->hitE();
1309}
1310
1312 return x + h->hitE() * h->hitX();
1313}
1314
1316 return x + h->hitE() * h->hitY();
1317}
1318
1320 return x + h->hitE() * h->hitZ();
1321}
1322
1324 return x + h->hitE() * h->hitT();
1325}
1326
1328 return h->hitColumn() == 0 ? x + h->hitE() : x;
1329}
1330
1331
1332// M. Mathison 1 Feb. 2024: Changed energy weighting for clX and clY functions
1333// to be logarithmic instead of linear. W0 set to 4 as default, but ideally
1334// its energy dependence should be found from simulation
1335
1336// Y coordinate of center of gravity of cluster, calculated as logarithmic hit
1337// energy weighted average. Put X out of the calorimeter (-100 cm), if there is
1338// no energy deposition in the cluster.
1339//
1341 Double_t x = 0;
1342 Double_t Wtot = 0;
1343 Double_t hitW = 0;
1344 Double_t W0 = 4;
1345 Double_t Etot = accumulate((*cluster).begin(),(*cluster).end(),0.,addE);
1346 for (THcNPSShowerClusterIt pph = (*cluster).begin(); pph != (*cluster).end(); ++pph) {
1347 hitW = (W0 + TMath::Log((*pph)->hitE()/Etot) > 0. ? W0 + TMath::Log((*pph)->hitE()/Etot) : 0.);
1348 Wtot += hitW;
1349 x += hitW * (*pph)->hitY();
1350 }
1351 return (Wtot != 0. ? x/Wtot : -100.);
1352}
1353// X coordinate of center of gravity of cluster, calculated as logarithmic hit
1354// energyweighted average. Put X out of the calorimeter (-100 cm), if there is
1355// no energy deposition in the cluster.
1356//
1358 Double_t x = 0;
1359 Double_t Wtot = 0;
1360 Double_t hitW = 0;
1361 Double_t W0 = 4;
1362 Double_t Etot = accumulate((*cluster).begin(),(*cluster).end(),0.,addE);
1363 for (THcNPSShowerClusterIt pph = (*cluster).begin(); pph != (*cluster).end(); ++pph) {
1364 hitW = (W0 + TMath::Log((*pph)->hitE()/Etot) > 0. ? W0 + TMath::Log((*pph)->hitE()/Etot) : 0.);
1365 Wtot += hitW;
1366 x += hitW * (*pph)->hitX();
1367 }
1368 return (Wtot != 0. ? x/Wtot : -100.);
1369}
1370
1371// Z coordinate of center of gravity of cluster, calculated as a hit energy
1372// weighted average. Put Z out of the calorimeter (0 cm), if there is no energy
1373// deposition in the cluster.
1374//
1376 Double_t Etot = accumulate((*cluster).begin(),(*cluster).end(),0.,addE);
1377 return (Etot != 0. ?
1378 accumulate((*cluster).begin(),(*cluster).end(),0.,addZ)/Etot : 0.);
1379}
1380
1381
1382// Time of cluster, calculated as a hit energy weighted average.
1383// Put T at 0 ns if there is no energy deposition in cluster.
1384//
1386 Double_t Etot = accumulate((*cluster).begin(),(*cluster).end(),0.,addE);
1387 return (Etot != 0. ?
1388 accumulate((*cluster).begin(),(*cluster).end(),0.,addT)/Etot : 0.);
1389}
1390
1391//Energy depostion in a cluster
1392//
1394 return accumulate((*cluster).begin(),(*cluster).end(),0.,addE);
1395}
1396
1397//Energy deposition in the Preshower (1st plane) for a cluster
1398//
1400 return accumulate((*cluster).begin(),(*cluster).end(),0.,addEpr);
1401}
1402
1403//Cluster energy deposition in plane iplane=0,..,3:
1404// side=0 -- from positive PMTs only;
1405// side=1 -- from negative PMTs only;
1406// side=2 -- from postive and negative PMTs.
1407//
1408
1410
1411 if (side!=0&&side!=1&&side!=2) {
1412 cout << "*** Wrong Side in clEplane:" << side << " ***" << endl;
1413 return -1;
1414 }
1415
1416 THcNPSShowerHitSet pcluster;
1417 for (THcNPSShowerHitIt it=(*cluster).begin(); it!=(*cluster).end(); ++it) {
1418 if ((*it)->hitColumn() == iplane) pcluster.insert(*it);
1419 }
1420
1421 Double_t Eplane;
1422 switch (side) {
1423 /*
1424 case 0 :
1425 Eplane = accumulate(pcluster.begin(),pcluster.end(),0.,addEpos);
1426 break;
1427 case 1 :
1428 Eplane = accumulate(pcluster.begin(),pcluster.end(),0.,addEneg);
1429 break;
1430 */
1431 case 2 :
1432 Eplane = accumulate(pcluster.begin(),pcluster.end(),0.,addE);
1433 break;
1434
1435 default :
1436 Eplane = 0. ;
1437 }
1438
1439 return Eplane;
1440}
1441
1442//_____________________________________________________________________________
1444{
1445
1446 //cout << "Calling THcNPSCalorimeter::FineProcess() . . . " << endl;
1447 return 0;
1448}
1449
1453//_____________________________________________________________________________
1455{
1456 // cout<< "Calling THcNPSCalorimeter::End() . . . " << endl;
1457
1458 MissReport(Form("%s.%s", GetApparatus()->GetName(), GetName()));
1459 return 0;
1460}
1461
int Int_t
unsigned int UInt_t
void clear()
Definition VLDModule.h:1
#define d(i)
bool Bool_t
float Float_t
double Double_t
const Bool_t kTRUE
const char Option_t
#define TESTBIT(n, i)
Option_t Option_t TPoint TPoint const char mode
R__EXTERN class THaVarList * gHaVars
R__EXTERN class THaCutList * gHaCuts
ClassImp(VDC::AnalyticTTDConv) using namespace std
R__EXTERN class THcParmList * gHcParms
R__EXTERN class THcDetectorMap * gHcDetectorMap
Double_t addX(Double_t x, THcNPSShowerHit *h)
Double_t clT(THcNPSShowerCluster *cluster)
Double_t clX(THcNPSShowerCluster *cluster)
Double_t addE(Double_t x, THcNPSShowerHit *h)
Double_t addT(Double_t x, THcNPSShowerHit *h)
Double_t clEplane(THcNPSShowerCluster *cluster, Int_t iplane, Int_t side)
Double_t clE(THcNPSShowerCluster *cluster)
Double_t addEpr(Double_t x, THcNPSShowerHit *h)
Double_t clY(THcNPSShowerCluster *cluster)
Double_t addZ(Double_t x, THcNPSShowerHit *h)
Double_t clZ(THcNPSShowerCluster *cluster)
Double_t clEpr(THcNPSShowerCluster *cluster)
Double_t addY(Double_t x, THcNPSShowerHit *h)
Double_t clT(THcNPSShowerCluster *cluster)
Double_t clX(THcNPSShowerCluster *cluster)
Double_t clE(THcNPSShowerCluster *cluster)
Double_t clY(THcNPSShowerCluster *cluster)
Double_t clZ(THcNPSShowerCluster *cluster)
THcNPSShowerCluster::iterator THcNPSShowerClusterIt
THcNPSShowerClusterList::iterator THcNPSShowerClusterListIt
vector< THcNPSShowerCluster * > THcNPSShowerClusterList
THcNPSShowerHitSet THcNPSShowerCluster
THcNPSShowerHitSet::iterator THcNPSShowerHitIt
set< THcNPSShowerHit * > THcNPSShowerHitSet
R__EXTERN TRandom * gRandom
char * Form(const char *fmt,...)
virtual std::vector< UInt_t > GetConnectorID()
Definition VLDModule.h:37
virtual std::vector< UInt_t > GetChannelMask()
Definition VLDModule.h:35
virtual std::vector< UInt_t > GetLoHiBit()
Definition VLDModule.h:36
virtual std::vector< UInt_t > GetTriggerType1()
Definition VTPModule.h:40
virtual std::vector< UInt_t > GetClusterEnergy()
Definition VTPModule.h:46
virtual std::vector< UInt_t > GetTriggerType3()
Definition VTPModule.h:42
virtual std::vector< UInt_t > GetTriggerTime()
Definition VTPModule.h:38
virtual std::vector< UInt_t > GetTriggerType0()
Definition VTPModule.h:39
virtual UInt_t GetTriggerNum()
Definition VTPModule.h:36
virtual std::vector< UInt_t > GetTriggerType2()
Definition VTPModule.h:41
virtual std::vector< UInt_t > GetTriggerType5()
Definition VTPModule.h:44
virtual std::vector< UInt_t > GetClusterX()
Definition VTPModule.h:49
virtual std::vector< UInt_t > GetClusterTime()
Definition VTPModule.h:47
virtual std::vector< UInt_t > GetClusterY()
Definition VTPModule.h:50
virtual std::vector< UInt_t > GetTriggerType4()
Definition VTPModule.h:43
virtual std::vector< UInt_t > GetClusterSize()
Definition VTPModule.h:48
static Int_t DefineVarsFromList(const void *list, EType type, EMode mode, const char *def_prefix, const TObject *obj, const char *prefix, const char *here, const char *comment_subst="")
virtual const char * Here(const char *) const
Int_t RemoveVariables()
static THaAnalyzer * GetInstance()
Double_t X() const
Double_t Y() const
Double_t Z() const
virtual Int_t Result(const char *cutname="", EWarnMode mode=kWarn)
UInt_t GetSize() const
Module * GetModule(UInt_t i) const
UInt_t GetTotNumChan() const
THaDetMap * fDetMap
virtual void DefineAxes(Double_t rotation_angle)
THaApparatus * GetApparatus() const
UInt_t GetEvNum() const
virtual Decoder::Module * GetModule(UInt_t roc, UInt_t slot) const
virtual THaVar * Find(const char *name) const
const void * GetValuePointer() const
virtual Int_t FillMap(THaDetMap *detmap, const char *detectorname)
virtual Int_t DecodeToHitList(const THaEvData &evdata, Bool_t suppress=kFALSE)
TClonesArray * fRawHitList
void MissReport(const char *name)
void CreateMissReportParms(const char *prefix)
void InitHitList(THaDetMap *detmap, const char *hitclass, Int_t maxhits, Int_t tdcref_cut=0, Int_t adcref_cut=0)
Int_t fADC_RefTimeCut
Bool_t GetClearThisEvent()
virtual EStatus Init(const TDatime &run_time)
virtual Int_t AccumulatePedestals(TClonesArray *rawhits, Int_t nexthit)
virtual Int_t CoarseProcessHits()
Double_t fvYmax()
Double_t fvXmin()
virtual void CalculatePedestals()
virtual void Clear(Option_t *opt="")
virtual Int_t ClearProcessedHits()
Double_t fvYmin()
virtual Int_t AccumulateHits(TClonesArray *rawhits, Int_t nexthit, Int_t quadrant)
virtual Int_t CoarseProcess(TClonesArray &tracks)
Double_t fvXmax()
Int_t GetNeighbor(UInt_t id, UInt_t k)
void GetMax(Float_t pInei[8], Int_t nei[8], Int_t &virus_blk, Float_t &max)
Double_t GetEarray()
Definition THcNPSArray.h:96
Generic segmented shower detector.
std::vector< Double_t > fClusterZ
THcNPSShowerClusterList * fClusterList
std::vector< UInt_t > fVLDColumn
static const Int_t kADCDynamicPedestal
virtual Int_t End(THaRunBase *r=0)
void ClusterHits(THcNPSShowerHitSet &HitSet, THcNPSShowerClusterList *ClusterList)
std::vector< THcNPSCluster > fClusters
virtual void Clear(Option_t *opt="")
std::vector< UInt_t > fVTPClusterY
std::vector< UInt_t > fVTPTriggerType2
std::vector< UInt_t > fVLDRow
std::vector< UInt_t > fVTPClusterEnergy
void Setup(const char *name, const char *description)
std::vector< UInt_t > fVTPClusterTime
static const Int_t fnVLD
std::vector< UInt_t > fVTPTriggerType4
std::vector< UInt_t > fVTPClusterSize
std::vector< UInt_t > fVTPTriggerType3
std::vector< Int_t > fVTPTriggerCrate
std::vector< Double_t > fClusterE
std::vector< UInt_t > fVTPTriggerType1
std::vector< UInt_t > fVLDPMT
std::vector< UInt_t > fVTPClusterX
virtual Int_t DefineVariables(EMode mode=kDefine)
THcNPSAnalyzer * fAnalyzer
virtual Int_t Decode(const THaEvData &)
std::vector< Double_t > fClusterY
std::vector< UInt_t > fVTPTriggerType0
std::vector< UInt_t > fVLDHiChannelMask
static const Int_t fnVTP
std::vector< Double_t > fClusterT
std::vector< Double_t > fClusterX
std::vector< UInt_t > fVLDLoChannelMask
virtual Int_t CoarseProcess(TClonesArray &tracks)
virtual Int_t FineProcess(TClonesArray &tracks)
std::vector< UInt_t > fVTPTriggerType5
std::vector< UInt_t > fVTPTriggerTime
virtual Int_t ReadDatabase(const TDatime &date)
void ClusterNPS_Hits(THcNPSShowerHitSet &HitSet, THcNPSShowerClusterList *ClusterList)
Double_t E() const
void AddBlock(Int_t blockID)
Double_t T() const
Int_t LoadParmValues(const DBRequest *list, const char *prefix="")
const char * GetName() const override
const char * GetTitle() const override
virtual void Error(const char *method, const char *msgfmt,...) const
virtual UInt_t Integer(UInt_t imax)
Double_t x[n]
TH1 * h
double max(double x, double y)
end
Double_t Min(Double_t a, Double_t b)
Double_t Log(Double_t x)
Double_t Max(Double_t a, Double_t b)
STL namespace.
void tracks()