Skip to content

Strip Threshold Finder app - first functional version#143

Draft
JarredMRoberts wants to merge 1 commit into
cositools:develop/emfrom
JarredMRoberts:strip-threshold-finder
Draft

Strip Threshold Finder app - first functional version#143
JarredMRoberts wants to merge 1 commit into
cositools:develop/emfrom
JarredMRoberts:strip-threshold-finder

Conversation

@JarredMRoberts

Copy link
Copy Markdown

This threshold finder app locates the slow and fast energy threshold values of all channels of a given dataset. The threshold values are saved to independent csv files, and a ROOT data file is also created in the same directory where the input file is found. There are several diagnostic plots that can be generated in ROOT. Examples of commands for how to generate these plots are printed to the terminal.

An example yaml input file is also included that is used to add the paths to your data file(s), calibration files, strip map file, some variables for the threshold finding algorithm, and the output file names.

@zoglauer

Copy link
Copy Markdown
Collaborator

Hi Jarred,

That's a tiny bit of spaghetti code, that you produced there...
You have to make a nice class out of it. But, e.g., Claude can do that for you. Here is a draft from Claude:

//! Finds per-strip slow and fast energy thresholds for germanium detectors
class MStripThresholdFinder
{
public:
//! Default constructor
MStripThresholdFinder();

//! Parse YAML config file and command line overrides; returns false on error
bool ParseCommandLine(int Argc, char** Argv);

//! Read HDF data files and fill raw ADC and timing histograms
bool BuildHistograms();

//! Find slow (energy-based) thresholds via noise-peak algorithm
void FindSlowThresholds();

//! Find fast (timing-based) thresholds via dt0/dt1 crossover
void FindFastThresholds();

//! Write slow and fast threshold CSV files
void WriteCSV() const;

//! Write ROOT file with all diagnostic plots
void WriteDiagnostics() const;

private:
// Configuration
//! Input HDF5 data files
vector m_InputFiles;
//! Slow-shaper energy calibration file path
MString m_CalibrationFile;
//! TAC calibration file path
MString m_TACCalibrationFile;
//! Strip map file path
MString m_StripMapFile;
//! Output file prefix
MString m_OutputPrefix;
//! Minimum histogram entries required before applying threshold algorithm
int m_MinEntries = 10;
//! Threshold assigned when algorithm cannot converge (keV)
double m_FallbackThreshold = 20.0;
//! Number of bins in ADC histograms
int m_HistogramBins = 2048;
//! Maximum ADC value for histogram range
double m_HistogramMaxADC = 4096.0;
//! Upper ADC limit used when searching for the noise peak
double m_NoiseSearchMaxADC = 2200.0;
//! Maximum number of events to process; -1 means unlimited
long m_MaxEvents = -1;

// Calibration helpers
//! Slow-shaper ADC-to-energy calibration
MEnergyCalibrationHelper m_EnergyCal;
//! TAC ADC-to-energy calibration
MTACCalibrationHelper m_TACCal;

// Raw data
//! Per-strip ADC histograms filled from slow-shaper data
map<StripKey, TH1D*> m_ADCHistograms;
//! Per-strip TAC ADC histograms
map<StripKey, TH1D*> m_TACHistograms;
//! Per-strip, per-ADC bin counts of dt0 (no fast timing) and dt1 (has fast timing) hits
map<StripKey, map<int, pair<int, int>>> m_TimingCounts;

// Results
//! Slow threshold per strip in keV
map<StripKey, double> m_SlowThresholds;
//! Slow threshold per strip in ADC counts
map<StripKey, double> m_SlowThresholdsADC;
//! Fast threshold per strip in keV
map<StripKey, double> m_FastThresholds;
//! Fast threshold per strip in ADC counts
map<StripKey, double> m_FastThresholdsADC;

//! Find the bin of the noise peak within the search window
int FindNoisePeakBin(TH1D* Histogram) const;
//! Find the threshold bin at the trough immediately right of the noise peak
int FindThresholdBin(TH1D* Histogram, int PeakBin) const;
//! Find the ADC value where dt1 counts first exceed dt0 counts
int FindCrossoverADC(const map<int, pair<int, int>>& ADCMap, int FirstNonzero) const;

};

////////////////////////////////////////////////////////////////////////////////

int main(int Argc, char** Argv)
{
setvbuf(stdout, NULL, _IONBF, 0);
MGlobal::Initialize("Standalone", "ThresholdFinder");

MStripThresholdFinder Finder;
if (!Finder.ParseCommandLine(Argc, Argv)) return 1;
if (!Finder.BuildHistograms()) return 1;
Finder.FindSlowThresholds();
Finder.FindFastThresholds();
Finder.WriteCSV();
Finder.WriteDiagnostics();

return 0;

}

Tell him to follow the style guide: CodingConventions.md - and he will do the rest.

In addition, your helpers, are they just loading the standard energy calibration and TAC calibration?
Then please use the existing code via this pattern:

MModuleTACcut TACCut;
TACCut.SetTACCalFileName(m_TACCalFileName);
if (TACCut.LoadTACCalFile(m_TACCalFileName) == true){
// copy the data over
}

Felix is doing the same for his code, thus you can just wait until he has implemented it and the reuse the pattern he has.

@fhagemann

Copy link
Copy Markdown

You can find how I reused existing code in #134 and/or #144 :)

@fhagemann

Copy link
Copy Markdown

Also, is this PR based on the current main and supposed to be merged into main? Or is that for develop/em?

@fhagemann

Copy link
Copy Markdown

Also, how does this PR relate to #129 ?

@zoglauer

Copy link
Copy Markdown
Collaborator

Also, is this PR based on the current main and supposed to be merged into main? Or is that for develop/em?

I didn't see that - every addition should go into develop/em.

@JarredMRoberts

JarredMRoberts commented May 26, 2026 via email

Copy link
Copy Markdown
Author

@JarredMRoberts JarredMRoberts changed the base branch from main to develop/em June 2, 2026 00:56
@JarredMRoberts JarredMRoberts marked this pull request as draft June 2, 2026 00:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants