From 00db06452ba0697b3283770df3ea3d6361f3826f Mon Sep 17 00:00:00 2001 From: Steven Doran <78985334+S81D@users.noreply.github.com> Date: Tue, 7 Oct 2025 11:34:55 -0500 Subject: [PATCH 1/5] Update Factory.cpp Add PrintADCTraces to factory --- UserTools/Factory/Factory.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/UserTools/Factory/Factory.cpp b/UserTools/Factory/Factory.cpp index 7d1366c60..05b30466b 100644 --- a/UserTools/Factory/Factory.cpp +++ b/UserTools/Factory/Factory.cpp @@ -176,5 +176,6 @@ if (tool=="AssignBunchTimingMC") ret=new AssignBunchTimingMC; if (tool=="FitRWMWaveform") ret=new FitRWMWaveform; if (tool=="PMTWaveformSim") ret=new PMTWaveformSim; if (tool=="LAPPDWaveformDisplay") ret=new LAPPDWaveformDisplay; +if (tool=="PrintADCTraces") ret=new PrintADCTraces; return ret; } From 3162d11d768948ec82922980957a0968082d7482 Mon Sep 17 00:00:00 2001 From: Steven Doran <78985334+S81D@users.noreply.github.com> Date: Tue, 7 Oct 2025 11:35:29 -0500 Subject: [PATCH 2/5] Update Unity.h add to unity --- UserTools/Unity.h | 1 + 1 file changed, 1 insertion(+) diff --git a/UserTools/Unity.h b/UserTools/Unity.h index ea9fdd96d..528064ce2 100644 --- a/UserTools/Unity.h +++ b/UserTools/Unity.h @@ -184,3 +184,4 @@ #include "FitRWMWaveform.h" #include "PMTWaveformSim.h" #include "LAPPDWaveformDisplay.h" +#include "PrintADCTraces.h" From 71d171873f674c07a1c2b9e976e60681ad3e9331 Mon Sep 17 00:00:00 2001 From: Steven Doran <78985334+S81D@users.noreply.github.com> Date: Tue, 7 Oct 2025 11:55:57 -0500 Subject: [PATCH 3/5] New PrintADCTraces tool --- UserTools/PrintADCTraces/PrintADCTraces.cpp | 285 ++++++++++++++++++++ UserTools/PrintADCTraces/PrintADCTraces.h | 71 +++++ UserTools/PrintADCTraces/README.md | 72 +++++ 3 files changed, 428 insertions(+) create mode 100644 UserTools/PrintADCTraces/PrintADCTraces.cpp create mode 100644 UserTools/PrintADCTraces/PrintADCTraces.h create mode 100644 UserTools/PrintADCTraces/README.md diff --git a/UserTools/PrintADCTraces/PrintADCTraces.cpp b/UserTools/PrintADCTraces/PrintADCTraces.cpp new file mode 100644 index 000000000..0b9189e36 --- /dev/null +++ b/UserTools/PrintADCTraces/PrintADCTraces.cpp @@ -0,0 +1,285 @@ +#include + +#include "ANNIEconstants.h" +#include "PrintADCTraces.h" + +#include "TGraph.h" + +PrintADCTraces::PrintADCTraces():Tool(){} + +// Tool will loop over hits, extract ADC traces from the RecoADCData, and output those traces to a root file + +// output root file structure +// ROOT file: +// ├── chankey/ # directory for each PMT channel +// ├── 332/ +// │ ├── wf1 TGraph # for each pulse, a TGraph +// │ └── wf2 TGraph +// ├── 463/ +// │ ├── wf1 TGraph +// │ └── ... +// └── TraceSummary TTree # metadata +// ├── chan # all pulse channel ids +// ├── run # all pulse run numbers +// ├── eventTime # all pulse event times +// ├── hitT # all pulse hit times [ns] +// ├── hitPE # all pulse hit charges [pe] +// ├── hitBaseline # all pulse baselines [adc] +// └── hitNoise # all pulse baseline sigma (noise) [adc] + + +bool PrintADCTraces::Initialise(std::string configfile, DataModel &data) +{ + + /////////////////// Useful header /////////////////////// + if(configfile!="") m_variables.Initialise(configfile); // loading config file + + m_data= &data; //assigning transient data pointer + ///////////////////////////////////////////////////////////////// + + // get config variables + + bool gotVerbosity = m_variables.Get("verbosity", verbosity); + if (!gotVerbosity) verbosity = 1; + + // range of hit charges to save + gotPEmin = m_variables.Get("hitPE_min", fhitPEmin); + if (!gotPEmin) { + logmessage = "PrintADCTraces: hitPE_min not defined. No selection will be imposed."; + Log(logmessage, v_error, verbosity); + } + gotPEmax = m_variables.Get("hitPE_max", fhitPEmax); + if (!gotPEmax) { + logmessage = "PrintADCTraces: hitPE_max not defined. No selection will be imposed."; + Log(logmessage, v_error, verbosity); + } + + // save only hit times in a certain range (useful for laser peak or beam spill) + gotTmin = m_variables.Get("hitT_min", fhitTmin); + if (!gotTmin) { + logmessage = "PrintADCTraces: hitT_min not defined. No selection will be imposed."; + Log(logmessage, v_error, verbosity); + } + gotTmax = m_variables.Get("hitT_max", fhitTmax); + if (!gotTmax) { + logmessage = "PrintADCTraces: hitT_max not defined. No selection will be imposed."; + Log(logmessage, v_error, verbosity); + } + + // maximum number of total traces saved - this could explode depending on how many events we run over + bool gotMaxTraces = m_variables.Get("MaxTraces", fMaxTraces); + if (!gotMaxTraces) { + logmessage = "PrintADCTraces: MaxTraces not defined. Using default of 10000."; + Log(logmessage, v_error, verbosity); + fMaxTraces = 10000; + } + + // per individual channel, how many traces do you want? + bool gotMaxTracesPerChan = m_variables.Get("MaxTracesPerChannel", fMaxTracesPerChan); + if (!gotMaxTracesPerChan) { + logmessage = "PrintADCTraces: MaxTracesPerChannel not defined. Setting no limit on traces per channel, will default to filling according to MaxTraces argument."; + Log(logmessage, v_error, verbosity); + fMaxTracesPerChan = 0; + } + + // name of the output root file containing trace data + bool gotOutputFilename = m_variables.Get("OutputFilename", filename); + if (!gotOutputFilename) { + logmessage = "PrintADCTraces: OutputFilename not defined. Setting output file name to: 'ADCTraces.root'"; + Log(logmessage, v_error, verbosity); + filename = "ADCTraces.root"; + } + + // set up output file + fOutFile = new TFile(filename.c_str(), "RECREATE"); + + // summary TTree containing global distribution of all saved ADC traces + fTraceSummaryTree = new TTree("TraceSummary", "Summary of saved ADC traces"); + fTraceSummaryTree->Branch("chan", &fchan); + fTraceSummaryTree->Branch("run", &frun); + fTraceSummaryTree->Branch("eventTime", &feventTime); + fTraceSummaryTree->Branch("hitT", &fhitT); + fTraceSummaryTree->Branch("hitPE", &fhitPE); + fTraceSummaryTree->Branch("hitBaseline", &fhitBaseline); + fTraceSummaryTree->Branch("hitNoise", &fhitNoise); + + return true; +} + +//------------------------------------------------------------------------------ +bool PrintADCTraces::Execute() +{ + Log("PrintADCTraces: Execute()", v_debug, verbosity); + + // *********************************** + // load stores + + bool goodAnnieEvent = m_data->Stores.count("ANNIEEvent"); + if (!goodAnnieEvent) { + logmessage = "PrintADCTraces: no ANNIEEvent store! Aborting!"; + Log(logmessage, v_error, verbosity); + return false; + } + + // need this for the nQ -> PE conversion + bool gotSPEmap = m_data->CStore.Get("ChannelNumToTankPMTSPEChargeMap",fChannelKeyToSPEMap); + if (!gotSPEmap) { + logmessage = "PrintADCTraces: could not find ChannelNumToTankPMTSPEChargeMap! Aborting!"; + Log(logmessage, v_error, verbosity); + return false; + } + + // ADCPulse class information (contains the traces) + bool got_recoadc = m_data->Stores["ANNIEEvent"]->Get("RecoADCData",fRecoADCData); + if (!got_recoadc) { + logmessage = "PrintADCTraces: could not find RecoADCData! Aborting!"; + Log(logmessage, v_error, verbosity); + return false; + } + + // TGraph title will be ____ + int fRunNumber = 9999; + int fPartFileNumber = 9999; + uint64_t fWaveformTime = 0; + + bool gotRunNumber = m_data->Stores["ANNIEEvent"]->Get("RunNumber", fRunNumber); + bool gotPartFile = m_data->Stores["ANNIEEvent"]->Get("PartNumber", fPartFileNumber); + bool gotTimestamp = m_data->Stores["ANNIEEvent"]->Get("EventTimeTank", fWaveformTime); + + if (!gotPartFile || !gotTimestamp || !gotRunNumber) { + logmessage = "PrintADCTraces: Error retrieving "; + if (!gotRunNumber) logmessage += "RunNumber "; + if (!gotPartFile) logmessage += "PartNumber "; + if (!gotTimestamp) logmessage += "EventTimeTank "; + logmessage += "from ANNIEEvent! Setting default (nonsense) values."; + Log(logmessage, v_error, verbosity); + } + + // *********************************** + // write out ADC traces + + fOutFile->cd(); // go to root of output file + + // loop through RecoADCData and fill the graphs with the ADC traces + for (auto& chan_pair : fRecoADCData) { + unsigned long chankey = chan_pair.first; + auto& minibuffers = chan_pair.second; + + int& chanGraphCount = graphsPerChannel[chankey]; + + // make/get directory + std::string chanStr = std::to_string(chankey); + TDirectory* dir = fOutFile->GetDirectory(chanStr.c_str()); + if (!dir) dir = fOutFile->mkdir(chanStr.c_str()); + dir->cd(); + + for (size_t mb_i = 0; mb_i < minibuffers.size(); ++mb_i) { + + // if the max trace limit is reached, stop looping over the minibuffers + if ((fMaxTraces != 0 && totalGraphs >= fMaxTraces) || + (fMaxTracesPerChan != 0 && chanGraphCount >= fMaxTracesPerChan)) { + break; + } + + const auto& pulsevec = minibuffers.at(mb_i); + + for (const auto& pulse : pulsevec) { + + double hitT = pulse.peak_time(); // interpolated hit time [ns] + double hitQ = pulse.charge(); // charge [nQ] + double hitBaseline = pulse.baseline(); // baseline [adc] + double hitNoise = pulse.sigma_baseline(); // noise [adc] + + // need to convert from nQ -> PE using SPE conversion map + auto spe_it = fChannelKeyToSPEMap.find(chankey); + double hitPE = -9999; + if (spe_it != fChannelKeyToSPEMap.end() && spe_it->second > 0) { + hitPE = hitQ / spe_it->second; + } else { + logmessage = "PrintADCTraces: Missing or invalid SPE value for channel " + std::to_string(chankey) + + ". Cannot convert to PE. Using placeholder -9999."; + Log(logmessage, v_warning, verbosity); + } + + // apply hitT and hitPE cuts (skip pulse if it doesn't pass) + bool passTime = (!gotTmin || hitT >= fhitTmin) && (!gotTmax || hitT <= fhitTmax); + bool passPE = (!gotPEmin || hitPE >= fhitPEmin) && (!gotPEmax || hitPE <= fhitPEmax); + if (!passTime || !passPE) continue; + + // construct TGraph title: ____ + std::stringstream grTitle; + grTitle << fRunNumber << "_" << fPartFileNumber << "_" << fWaveformTime + << "_" << std::fixed << std::setprecision(2) << hitT + << "_" << std::fixed << std::setprecision(2) << hitPE; + + // grab trace + const auto& xpts = pulse.GetTraceXPoints(); + const auto& ypts = pulse.GetTraceYPoints(); + + if (xpts.empty() || ypts.empty()) continue; + + // create and write to TGraph + TGraph gr(xpts.size()); + for (size_t i = 0; i < std::min(xpts.size(), ypts.size()); ++i) { + gr.SetPoint(i, xpts[i], ypts[i]); + } + gr.SetTitle(grTitle.str().c_str()); + gr.Write(); + + // write to summary TTree + fchan = chankey; + frun = fRunNumber; + feventTime = fWaveformTime; + fhitT = hitT; + fhitPE = hitPE; + fhitBaseline = hitBaseline; + fhitNoise = hitNoise; + fTraceSummaryTree->Fill(); + + ++totalGraphs; + ++chanGraphCount; + } + } + } + + logmessage = "PrintADCTraces: Total graphs written this event: " + std::to_string(totalGraphs); + Log(logmessage, v_debug, verbosity); + + return true; +} + +//------------------------------------------------------------------------------ +bool PrintADCTraces::Finalise() +{ + if (fOutFile) { + + if (fTraceSummaryTree) { // write summary to root file + fOutFile->cd(); + fTraceSummaryTree->Write(); + delete fTraceSummaryTree; // clean up clean up everybody do your share + fTraceSummaryTree = nullptr; + } + + fOutFile->cd(); + fOutFile->Write(); // write all contents to file + fOutFile->Close(); // close the ROOT file + delete fOutFile; // clean up the pointer + fOutFile = nullptr; + } + + Log("PrintADCTraces: Finished and closed output ROOT file.", v_debug, verbosity); + + logmessage = "PrintADCTraces: Total graphs written across all events: " + std::to_string(totalGraphs); + Log(logmessage, v_debug, verbosity); + for (const auto& entry : graphsPerChannel) { + logmessage = " Channel " + std::to_string(entry.first) + + " → " + std::to_string(entry.second) + " graphs"; + Log(logmessage, v_debug, verbosity); + } + + return true; +} + +//------------------------------------------------------------------------------ + +// done \ No newline at end of file diff --git a/UserTools/PrintADCTraces/PrintADCTraces.h b/UserTools/PrintADCTraces/PrintADCTraces.h new file mode 100644 index 000000000..b2319d7d1 --- /dev/null +++ b/UserTools/PrintADCTraces/PrintADCTraces.h @@ -0,0 +1,71 @@ +#ifndef PrintADCTraces_H +#define PrintADCTraces_H + +#include "Tool.h" +#include "TFile.h" +#include "TTree.h" +#include "TGraph.h" +#include "ADCPulse.h" +#include "Hit.h" + +/** + * \class PrintADCTraces + * + * \brief Tool to extract and store ADC traces in TGraphs + * + * $Author: S. Doran $ + * $Date: Apr 2025 $ + * Contact: doran@iastate.edu + */ +class PrintADCTraces: public Tool { + + + public: + + PrintADCTraces(); ///< Simple constructor + bool Initialise(std::string configfile,DataModel &data); ///< Initialise Function for setting up Tool resources. @param configfile The path and name of the dynamic configuration file to read in. @param data A reference to the transient data class used to pass information between Tools. + bool Execute(); ///< Execute function used to perform Tool purpose. + bool Finalise(); ///< Finalise function used to clean up resources. + + private: + + TFile* fOutFile = nullptr; // output root file + TTree* fTraceSummaryTree = nullptr; // summary TTree in root file + int fchan, frun; // branches in summary TTree + uint64_t feventTime; + float fhitT, fhitPE; + float fhitBaseline, fhitNoise; + + int totalGraphs = 0; // keep track how many TGraphs were written + std::map graphsPerChannel; + + float fhitTmin = 0; // config parameters + float fhitTmax = 0; + float fhitPEmin = 0; + float fhitPEmax = 0; + int fMaxTraces = 0; + int fMaxTracesPerChan = 0; + std::string filename; + + bool gotTmin = false; + bool gotTmax = false; + bool gotPEmin = false; + bool gotPEmax = false; + + // maps to Store objects + std::map>> fRecoADCData; + std::map fChannelKeyToSPEMap; + + int verbosity; + int v_error=0; + int v_warning=1; + int v_message=2; + int v_debug=3; + std::string logmessage; +}; + + +#endif + + + diff --git a/UserTools/PrintADCTraces/README.md b/UserTools/PrintADCTraces/README.md new file mode 100644 index 000000000..d0a102d66 --- /dev/null +++ b/UserTools/PrintADCTraces/README.md @@ -0,0 +1,72 @@ +# PrintADCTraces + +`PrintADCTraces` will read hit information (either from the "ClusterMap" or "Hits" from the "ANNIEEvent"), take the stored ADC traces in "RecoADCData", and output the traces to a root file. It will also filter traces/hits within some range of charges or times provided by the user. + +The tool is also useful to assemble metadata of data pulses, such as the calculated baseline and noise. This data (along with the shape of the ADC traces) can be used to analyze the stability of the PMTs over time. + +This tool does not put anything into the store. + +## Output rootfile + +`PrintADCTraces` produces a root file containing directories for each PMT channel - within each channel will be TGraphs for each ADC trace: + +``` +// ROOT file: +// ├── chankey/ # directory for each PMT channel +// ├── 332/ +// │ ├── wf1 TGraph # for each pulse, a TGraph +// │ └── wf2 TGraph +// ├── 463/ +// │ ├── wf1 TGraph +// │ └── ... +// └── TraceSummary TTree # metadata +// ├── chan # all pulse channel ids +// ├── run # all pulse run numbers +// ├── eventTime # all pulse event times +// ├── hitT # all pulse hit times [ns] +// ├── hitPE # all pulse hit charges [pe] +// ├── hitBaseline # all pulse baselines [adc] +// └── hitNoise # all pulse baseline sigma (noise) [adc] +``` + +where the TGraph name is given by: ```____``` + + +## Configuration +``` +# PrintADCTraces Config File + +verbosity 0 + +hitPE_min 0 # minimum hit charge [pe] to include in the root file +hitPE_max 2.5 # maximum hit charge [pe] to include in the root file + # omitting both of these will not impose a charge selection + +hitT_min 0 # minimum hit time [ns] to include in the root file +hitT_max 2000 # maximum hit time [ns] to include in the root file + # omitting both of these will not impose a time selection + +MaxTraces 10000 # maximum number of traces to include in the root file (default is 10,000 if not set by user) + # if set to '0', no limit will be imposed + +MaxTracesPerChannel 100 # maximum number of traces per channel to include in the root file + # if set to '0' or left undefined, it will not impose a limit + +useClusterHits 0 # fill root file with traces from clustered hits rather than from all event "Hits" + +OutputFilename ADCTraces.root # name of the output root file +``` + +## Example toolchain +``` +LoadANNIEEvent +LoadGeometry +ClusterFinder (only if you are using the clustered hits) +PrintADCTraces +``` + +## Additional information +- ADC traces will be in ADC (y) vs time [ns] (x). All pulse times will be relative (and zeroed) to the start time of the pulse. All pulse amplitudes (y) are baseline-subtracted. This way its easier to compare. You can cross reference the pulse features with the title (which contains the charge and time of the pulse) to determine more information. +- This tool is similar to `PrintADCData`, but instead of printing out all raw PMT waveforms, it only prints out the found pulse traces (and provides more identifying / filtering information based on charge / time). +- Runtime is ~30s for 10 part files (about the same whether or not `ClusterFinder` is included). +- Filesize for the output root file is ~0.05MB per waveform per channel. If including 100 waveforms per PMT channel(`MaxTracesPerChannel 100`) the filesize is ~5MB, if 1000 the filesize is ~50MB. From f7f0c2c1f705dce3c3be0ade52e43ebbf4fbacad Mon Sep 17 00:00:00 2001 From: Steven Doran <78985334+S81D@users.noreply.github.com> Date: Tue, 7 Oct 2025 12:03:15 -0500 Subject: [PATCH 4/5] PrintADCTraces working toolchain --- .../PrintADCTraces/ClusterFinderConfig | 12 ++++ .../PrintADCTraces/LoadANNIEEventConfig | 4 ++ .../PrintADCTraces/PrintADCTracesConfig | 19 ++++++ configfiles/PrintADCTraces/README.md | 68 +++++++++++++++++++ configfiles/PrintADCTraces/ToolChainConfig | 23 +++++++ configfiles/PrintADCTraces/ToolsConfig | 4 ++ configfiles/PrintADCTraces/my_inputs.txt | 10 +++ 7 files changed, 140 insertions(+) create mode 100644 configfiles/PrintADCTraces/ClusterFinderConfig create mode 100644 configfiles/PrintADCTraces/LoadANNIEEventConfig create mode 100644 configfiles/PrintADCTraces/PrintADCTracesConfig create mode 100644 configfiles/PrintADCTraces/README.md create mode 100644 configfiles/PrintADCTraces/ToolChainConfig create mode 100644 configfiles/PrintADCTraces/ToolsConfig create mode 100644 configfiles/PrintADCTraces/my_inputs.txt diff --git a/configfiles/PrintADCTraces/ClusterFinderConfig b/configfiles/PrintADCTraces/ClusterFinderConfig new file mode 100644 index 000000000..53330c25d --- /dev/null +++ b/configfiles/PrintADCTraces/ClusterFinderConfig @@ -0,0 +1,12 @@ +# ClusterFinder Config File + +verbosity 0 +HitStore Hits #Either MCHits or Hits (accessed in ANNIEEvent store) +OutputFile BeamRun_ClusterFinder_DefaultOutput #Output root prefix name for the current run +ClusterFindingWindow 40 # in ns, size of the window used to "clusterize" +AcqTimeWindow 70000 # in ns, size of the acquisition window +ClusterIntegrationWindow 40 # in ns, all hits with +/- 1/2 of this window are considered in the cluster +MinHitsPerCluster 5 # group of hits are considered clusters above this amount of hits +end_of_window_time_cut 0.95 # from o to 1, length of the window you want to loop over with respect to acq. window (1 for full window, 0.95 for 95% from the start) +Plots2D 0 #Draw 2D charge-vs-time plots? +ChankeyToPMTIDMap ./configfiles/EventDisplay/Data-RecoEvent/Chankey_WCSimID.dat diff --git a/configfiles/PrintADCTraces/LoadANNIEEventConfig b/configfiles/PrintADCTraces/LoadANNIEEventConfig new file mode 100644 index 000000000..284622ea2 --- /dev/null +++ b/configfiles/PrintADCTraces/LoadANNIEEventConfig @@ -0,0 +1,4 @@ +verbose 1 +FileForListOfInputs ./configfiles/PrintADCTraces/my_inputs.txt +EventOffset 0 +GlobalEvNr 1 diff --git a/configfiles/PrintADCTraces/PrintADCTracesConfig b/configfiles/PrintADCTraces/PrintADCTracesConfig new file mode 100644 index 000000000..223d13be8 --- /dev/null +++ b/configfiles/PrintADCTraces/PrintADCTracesConfig @@ -0,0 +1,19 @@ +verbosity 0 + +hitPE_min 0 # minimum hit charge [pe] to include in the root file +hitPE_max 2.5 # maximum hit charge [pe] to include in the root file + # omitting both of these will not impose a charge selection + +hitT_min 0 # minimum hit time [ns] to include in the root file +hitT_max 2000 # maximum hit time [ns] to include in the root file + # omitting both of these will not impose a time selection + +MaxTraces 10000 # maximum number of traces to include in the root file (default is 10,000 if not set by user) + # if set to '0', no limit will be imposed + +MaxTracesPerChannel 100 # maximum number of traces per channel to include in the root file + # if set to '0' or left undefined, it will not impose a limit + +useClusterHits 0 # fill root file with traces from clustered hits rather than from all event "Hits" + +OutputFilename ADCTraces.root # name of the output root file \ No newline at end of file diff --git a/configfiles/PrintADCTraces/README.md b/configfiles/PrintADCTraces/README.md new file mode 100644 index 000000000..33abd3962 --- /dev/null +++ b/configfiles/PrintADCTraces/README.md @@ -0,0 +1,68 @@ +# PrintADCTraces + +`PrintADCTraces` toolchain will read the ADC traces in "RecoADCData", and output the pulses (and the pulse metadata such as the baseline, charge, time, etc...) to a root file. It will also filter traces/hits within some range of charges or times provided by the user. + +## Output rootfile + +`PrintADCTraces` produces a root file containing directories for each PMT channel - within each channel will be TGraphs for each ADC trace: + +``` +// ROOT file: +// ├── chankey/ # directory for each PMT channel +// ├── 332/ +// │ ├── wf1 TGraph # for each pulse, a TGraph +// │ └── wf2 TGraph +// ├── 463/ +// │ ├── wf1 TGraph +// │ └── ... +// └── TraceSummary TTree # metadata +// ├── chan # all pulse channel ids +// ├── run # all pulse run numbers +// ├── eventTime # all pulse event times +// ├── hitT # all pulse hit times [ns] +// ├── hitPE # all pulse hit charges [pe] +// ├── hitBaseline # all pulse baselines [adc] +// └── hitNoise # all pulse baseline sigma (noise) [adc] +``` + +where the TGraph name is given by: ```____``` + + +## Configuration +``` +# PrintADCTraces Config File + +verbosity 0 + +hitPE_min 0.5 # minimum hit charge [pe] to include in the root file +hitPE_max 2.5 # maximum hit charge [pe] to include in the root file + # omitting both of these will not impose a charge selection + +hitT_min 0 # minimum hit time [ns] to include in the root file +hitT_max 2000 # maximum hit time [ns] to include in the root file + # omitting both of these will not impose a time selection + +MaxTraces 10000 # maximum number of traces to include in the root file (default is 10,000 if not set by user) + # if set to '0', no limit will be imposed + +MaxTracesPerChannel 100 # maximum number of traces per channel to include in the root file + # if set to '0' or left undefined, it will not impose a limit + +useClusterHits 0 # fill root file with traces from clustered hits rather than from all event "Hits" + +OutputFilename ADCTraces.root # name of the output root file +``` + +## Example toolchain +``` +LoadANNIEEvent +LoadGeometry +ClusterFinder (only if you are using the clustered hits) +PrintADCTraces +``` + +## Additional information +- ADC traces will be in ADC (y) vs time [ns] (x). All pulse times will be relative (and zeroed) to the start time of the pulse. All pulse amplitudes (y) are baseline-subtracted. This way its easier to compare. You can cross reference the pulse features with the title (which contains the charge and time of the pulse) to determine more information. +- This tool is similar to the `PrintADCData` toolchain, but instead of printing out all raw PMT waveforms, it only prints out the found pulse traces (and provides more identifying / filtering information based on charge / time). +- Runtime is ~30s for 10 part files (about the same whether or not `ClusterFinder` is included). +- Filesize for the output root file is ~0.05MB per waveform per channel. If including 100 waveforms per PMT channel(`MaxTracesPerChannel 100`) the filesize is ~5MB, if 1000 the filesize is ~50MB. diff --git a/configfiles/PrintADCTraces/ToolChainConfig b/configfiles/PrintADCTraces/ToolChainConfig new file mode 100644 index 000000000..bfe534b1c --- /dev/null +++ b/configfiles/PrintADCTraces/ToolChainConfig @@ -0,0 +1,23 @@ +#ToolChain dynamic setup file + +##### Runtime Paramiters ##### +verbose 1 +error_level 0 # 0= do not exit, 1= exit on unhandeled errors only, 2= exit on unhandeled errors and handeled errors +attempt_recover 1 + +###### Logging ##### +log_mode Interactive # Interactive=cout , Remote= remote logging system "serservice_name Remote_Logging" , Local = local file log; +log_local_path ./log +log_service LogStore + +###### Service discovery ##### +service_publish_sec -1 +service_kick_sec -1 + +##### Tools To Add ##### +Tools_File ./configfiles/PrintADCTraces/ToolsConfig + +##### Run Type ##### +Inline -1 +Interactive 0 + diff --git a/configfiles/PrintADCTraces/ToolsConfig b/configfiles/PrintADCTraces/ToolsConfig new file mode 100644 index 000000000..1e9497f16 --- /dev/null +++ b/configfiles/PrintADCTraces/ToolsConfig @@ -0,0 +1,4 @@ +LoadGeometry LoadGeometry ./configfiles/LoadGeometry/LoadGeometryConfig +LoadANNIEEvent LoadANNIEEvent ./configfiles/PrintADCTraces/LoadANNIEEventConfig +#ClusterFinder ClusterFinder ./configfiles/PrintADCTraces/ClusterFinderConfig +PrintADCTraces PrintADCTraces ./configfiles/PrintADCTraces/PrintADCTracesConfig diff --git a/configfiles/PrintADCTraces/my_inputs.txt b/configfiles/PrintADCTraces/my_inputs.txt new file mode 100644 index 000000000..463a08792 --- /dev/null +++ b/configfiles/PrintADCTraces/my_inputs.txt @@ -0,0 +1,10 @@ +/pnfs/annie/persistent/processed/processingData_EBV2/processed_EBV2/R4695/ProcessedData_PMTLAPPD_R4695S0p0 +/pnfs/annie/persistent/processed/processingData_EBV2/processed_EBV2/R4695/ProcessedData_PMTLAPPD_R4695S0p1 +/pnfs/annie/persistent/processed/processingData_EBV2/processed_EBV2/R4695/ProcessedData_PMTLAPPD_R4695S0p2 +/pnfs/annie/persistent/processed/processingData_EBV2/processed_EBV2/R4695/ProcessedData_PMTLAPPD_R4695S0p3 +/pnfs/annie/persistent/processed/processingData_EBV2/processed_EBV2/R4695/ProcessedData_PMTLAPPD_R4695S0p4 +/pnfs/annie/persistent/processed/processingData_EBV2/processed_EBV2/R4695/ProcessedData_PMTLAPPD_R4695S0p5 +/pnfs/annie/persistent/processed/processingData_EBV2/processed_EBV2/R4695/ProcessedData_PMTLAPPD_R4695S0p6 +/pnfs/annie/persistent/processed/processingData_EBV2/processed_EBV2/R4695/ProcessedData_PMTLAPPD_R4695S0p7 +/pnfs/annie/persistent/processed/processingData_EBV2/processed_EBV2/R4695/ProcessedData_PMTLAPPD_R4695S0p8 +/pnfs/annie/persistent/processed/processingData_EBV2/processed_EBV2/R4695/ProcessedData_PMTLAPPD_R4695S0p9 From c4f1eade0dc57c97349613fa62e5347521444267 Mon Sep 17 00:00:00 2001 From: Steven Doran <78985334+S81D@users.noreply.github.com> Date: Wed, 22 Oct 2025 10:06:27 -0500 Subject: [PATCH 5/5] Update PrintADCTraces.cpp - condensed some code - added a name to the TGraph - removed the double delete --- UserTools/PrintADCTraces/PrintADCTraces.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/UserTools/PrintADCTraces/PrintADCTraces.cpp b/UserTools/PrintADCTraces/PrintADCTraces.cpp index 0b9189e36..c0b96d2ab 100644 --- a/UserTools/PrintADCTraces/PrintADCTraces.cpp +++ b/UserTools/PrintADCTraces/PrintADCTraces.cpp @@ -219,10 +219,8 @@ bool PrintADCTraces::Execute() if (xpts.empty() || ypts.empty()) continue; // create and write to TGraph - TGraph gr(xpts.size()); - for (size_t i = 0; i < std::min(xpts.size(), ypts.size()); ++i) { - gr.SetPoint(i, xpts[i], ypts[i]); - } + TGraph gr(xpts.size(), xpts.data(), ypts.data()); + gr.SetName(grTitle.str().c_str()); gr.SetTitle(grTitle.str().c_str()); gr.Write(); @@ -256,7 +254,6 @@ bool PrintADCTraces::Finalise() if (fTraceSummaryTree) { // write summary to root file fOutFile->cd(); fTraceSummaryTree->Write(); - delete fTraceSummaryTree; // clean up clean up everybody do your share fTraceSummaryTree = nullptr; } @@ -282,4 +279,4 @@ bool PrintADCTraces::Finalise() //------------------------------------------------------------------------------ -// done \ No newline at end of file +// done