Skip to content

Trapping correction branch - #181

Merged
sophieehaight merged 33 commits into
cositools:develop/emfrom
sophieehaight:trapping_correction_branch
Jul 24, 2026
Merged

sophieehaight merged 33 commits into
cositools:develop/emfrom
sophieehaight:trapping_correction_branch

Conversation

@sophieehaight

Copy link
Copy Markdown

Contains a new module for applying depth-based charge trapping correction to individual hit energies along with modules with GUI options and GUI expos. The branch also includes an app for characterizing trapping with Cs-137 data. The trapping correction module requires a csv parameter file as input: detector_0_trapping_parameters.csv

merging any upstream changes from the Cs-137 trapping app into the branch with the trapping correction module
@sophieehaight
sophieehaight requested a review from ckierans July 15, 2026 23:31
@fhagemann
fhagemann self-requested a review July 23, 2026 19:25

@fhagemann fhagemann left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had a quick glimpse, and it seems like you're duplicating some function from the MModuleDepthCalibration to use here. Consider avoiding that code duplication by calling the original functions directly.

Comment on lines +462 to +580
int MModuleTrappingCorrection::GetHitGrade(MHit* H){
// Function for choosing which Depth-to-CTD relation to use for a given event.
// At time of writing, intention is to choose a CTD based on sub-pixel region determined via charge sharing (Event "grade").
// 5 possible grades, and one Error Grade, -1. GRADE 4 is as yet uncategorized complicated geometry. GRADE 5 means multiple, presumably separated strip hits.

//organize x and y strips into vectors
if (H == nullptr) {
return -1;
}
if (H->GetNStripHits() == 0) {
// Error if no strip hits listed. Bad grade is returned
if (g_Verbosity >= c_Error) cout << m_XmlTag << "ERROR in MModuleTrappingCorrection: HIT WITH NO STRIP HITS" << endl;
return -1;
}

// Take a Hit and separate its activated p and n strips into separate vectors.
std::vector<MStripHit*> LVStrips;
std::vector<MStripHit*> HVStrips;
vector<int> LVStripIDs;
vector<int> HVStripIDs;
for (unsigned int j = 0; j < H->GetNStripHits(); ++j) {
MStripHit* SH = H->GetStripHit(j);
if (SH == nullptr ) {
if (g_Verbosity >= c_Error) cout << m_XmlTag << "ERROR in MModuleTrappingCorrection: Trapping Correction: got NULL strip hit :( " << endl;
return -1;
}
if (SH->GetEnergy() == 0 ) {
if (g_Verbosity >= c_Error) cout << m_XmlTag << "ERROR in MModuleTrappingCorrection: Trapping Correction: got strip without energy :( " << endl;
return -1;
}
if (SH->IsLowVoltageStrip()) {
LVStrips.push_back(SH);
LVStripIDs.push_back(SH->GetStripID());
}
else {
HVStrips.push_back(SH);
HVStripIDs.push_back(SH->GetStripID());
}
}

// If the same strip has multiple hits, this is a bad grade.
bool MultiHitX = H->GetStripHitMultipleTimesLV();
bool MultiHitY = H->GetStripHitMultipleTimesHV();
if (MultiHitX || MultiHitY) {
return 5;
}

if (LVStrips.size()>0 && HVStrips.size()>0) {
int HVmin = * std::min_element(HVStripIDs.begin(), HVStripIDs.end());
int HVmax = * std::max_element(HVStripIDs.begin(), HVStripIDs.end());

int LVmin = * std::min_element(LVStripIDs.begin(), LVStripIDs.end());
int LVmax = * std::max_element(LVStripIDs.begin(), LVStripIDs.end());

// If the strip hits are not all adjacent, it's a bad grade.
if ( ((HVmax - HVmin) >= (HVStrips.size())) || ((LVmax - LVmin) >= (LVStrips.size())) ) {
return 6;
}
}
else{
return -1;
}

int return_value;
// If 1 strip on each side, GRADE=0
// This represents the center of the pixel
if ( ((LVStrips.size() == 1) && (HVStrips.size() == 1)) || ((LVStrips.size() == 3) && (HVStrips.size() == 3)) ) {
return_value = 0;
}
// If 2 hits on N side and 1 on P, GRADE=1
// This represents the middle of the edges of the pixel
else if ( (LVStrips.size() == 1) && (HVStrips.size() == 2) ) {
return_value = 1;
}

// If 2 hits on P and 1 on N, GRADE=2
// This represents the middle of the edges of the pixel
else if ( (LVStrips.size() == 2) && (HVStrips.size() == 1) ) {
return_value = 2;
}

// If 2 strip hits on both sides, GRADE=3
// This represents the corners the pixel
else if ( (LVStrips.size() == 2) && (HVStrips.size() == 2) ) {
return_value = 3;
}

// If 3 hits on N side and 1 on P, GRADE=0
// This represents the middle of the pixel, near the p (LV) side of the detector.
else if ( (LVStrips.size() == 1) && (HVStrips.size() == 3) ) {
return_value = 0;
}

// If 3 hits on P and 1 on N, GRADE=0
// This represents the middle of the pixel, near the n (HV) side of the detector.
else if ( (LVStrips.size() == 3) && (HVStrips.size() == 1) ) {
return_value = 0;
}

// If 3 hits on N side and 2 on P, GRADE=0
// This represents the middle of the edge of the pixel, near the p (LV) side of the detector.
else if ( (LVStrips.size() == 2) && (HVStrips.size() == 3) ) {
return_value = 2;
}

// If 3 hits on P and 2 on N, GRADE=0
// This represents the middle of the edge of the pixel, near the n (HV) side of the detector.
else if ( (LVStrips.size() == 3) && (HVStrips.size() == 2) ) {
return_value = 1;
}

else {
// If more complicated than the above cases, return 4 for now.
// TODO: Handle more complicated charge distributions.
return_value = 4;
}

return return_value;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this identical to MModuleDepthCalibration::GetHitGrade?
If so, we could avoid code duplication here by calling the original MModuleDepthCalibration::GetHitGrade instead.

Comment on lines +106 to +140
bool MModuleTrappingCorrection::Initialize()
{

// The detectors need to be in the same order as DetIDs.
// ie DetID=0 should be the 0th detector in m_Detectors, DetID=1 should the 1st, etc.
vector<MDDetector*> DetList = m_Geometry->GetDetectorList();

// Look through the Geometry and get the names of all the detectors.
for (unsigned int i = 0; i < DetList.size(); ++i) {
// For now, DetID is in order of detectors, which puts contraints on how the geometry file should be written.
unsigned int DetID = i;

MDDetector* det = DetList[i];
vector<string> DetectorNames;
if (det->GetTypeName() == "Strip3D") {
if (det->GetNSensitiveVolumes() == 1) {
MDVolume* vol = det->GetSensitiveVolume(0);
string det_name = vol->GetName().GetString();

if (find(DetectorNames.begin(), DetectorNames.end(), det_name) == DetectorNames.end()) {
DetectorNames.push_back(det_name);

if (g_Verbosity >= c_Info) {
cout << "Found detector " << det_name << " corresponding to DetID=" << DetID << "." << endl;
}
m_DetectorIDs.push_back(DetID);
m_Detectors[DetID] = det;
} else {
if (g_Verbosity >= c_Error) {
cout<<"ERROR in MModuleTrappingCorrection::Initialize: Found a duplicate detector: "<<det_name<<endl;
}
}
}
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is also done in MModuleDepthCalibration, so maybe we can export this to a function of MModuleDepthCalibration and call that new function here as well to avoid code duplication.
Might also be relevant for #182

Comment on lines +205 to +209
if (Grade < 0){
H->SetNoDepth();
} else if (Grade > 4) { // GRADE=5 is some complicated geometry with multiple hits on a single strip. GRADE=6 means not all strips are adjacent.
H->SetNoDepth();
} else { // If the Grade is 0-4, we can handle it.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this already done in MModuleDepthCalibration (setting H->SetNoDepth())?

if (Grade < 0){
H->SetNoDepth();
Event->SetDepthCalibrationError("Error in depth calibration");
if (Grade == -1) {
++m_ErrorSH;
} else if (Grade == -2) {
++m_ErrorNullSH;
} else if (Grade == -3) {
++m_ErrorNoE;
}
} else if (Grade > 4) { // GRADE=5 is some complicated geometry with multiple hits on a single strip. GRADE=6 means not all strips are adjacent.
H->SetNoDepth();
Event->SetDepthCalibrationError("Multiple hits on single strip");
if (Grade==5) {
++m_Error5;
} else if (Grade==6) {
++m_Error6;
}

If this charge trapping module is called AFTER the depth calibration, not sure if this is needed here (?)

Comment on lines +317 to +338
MStripHit* MModuleTrappingCorrection::GetDominantStrip(vector<MStripHit*>& Strips, double& EnergyFraction)
{
double MaxEnergy = -numeric_limits<double>::max(); // AZ: When both energies are zero (which shouldn't happen) we still pick one
double TotalEnergy = 0.0;
MStripHit* MaxStrip = nullptr;

// Iterate through strip hits and get the strip with highest energy
for (const auto SH : Strips) {
double Energy = SH->GetEnergy();
TotalEnergy += Energy;
if (Energy > MaxEnergy) {
MaxStrip = SH;
MaxEnergy = Energy;
}
}
if (TotalEnergy == 0) {
EnergyFraction = 0;
} else {
EnergyFraction = MaxEnergy/TotalEnergy;
}
return MaxStrip;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This also exists in MModuleDepthCalibration, so no need to duplicate ;)

Comment on lines +89 to +96
//! Returns the strip with most energy from vector Strips, also gives back the energy fraction
MStripHit* GetDominantStrip(std::vector<MStripHit*>& Strips, double& EnergyFraction);

// //! Retrieve the appropriate Depth values given the DetID
// vector<double> GetDepth(int DetID);

//! Determine the Grade (geometry of charge sharing) of the Hit
int GetHitGrade(MHit* H);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can also be removed (maybe check #144 for how we avoided code duplication in the DEE by reusing function from the energy calibration module).

@sophieehaight
sophieehaight merged commit 7bc061c into cositools:develop/em Jul 24, 2026
1 check passed
@fhagemann

Copy link
Copy Markdown

This PR was merged by accident and we removed the commits from develop/em.

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.

2 participants