-
Notifications
You must be signed in to change notification settings - Fork 12
Added GR and shield veto functionality #114
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop/em
Are you sure you want to change the base?
Changes from all commits
e159089
fa58d87
8423bd8
8c02502
cb79328
5814139
1390927
3022550
408664d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -92,7 +92,7 @@ class MSubModuleStripTrigger : public MSubModule | |
| double GetStripsTotalDeadtime() const { return m_StripsTotalDeadtime; } | ||
|
|
||
| //! Get number of strip hits erased | ||
| int GetStripHitsErased() const { return m_StripHitsErased; } | ||
| // int GetStripHitsErased() const { return m_StripHitsErased; } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you comment on why you removed
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No other modules uses this and this was only used for the printing at the end of the StripTriggerModule. This was just meant to be a diagnostic printout. |
||
|
|
||
| //! Get trigger rate for detector | ||
| int GetTriggerRate(int det) const { | ||
|
|
@@ -174,9 +174,11 @@ class MSubModuleStripTrigger : public MSubModule | |
| //! Stores total dead time of the instrument | ||
| double m_StripsTotalDeadtime; | ||
| //! Hits erased due to deadtime | ||
| int m_StripHitsErased; | ||
| // int m_StripHitsErased; | ||
| //! Total strip hits counter | ||
| int m_TotalStripHitsCounter; | ||
| //! Total GR hits counter | ||
| int m_TotalGRHitsCounter; | ||
|
|
||
| //! First event time for statistics | ||
| double m_FirstTime; | ||
|
|
@@ -186,7 +188,7 @@ class MSubModuleStripTrigger : public MSubModule | |
| //! Number of detectors | ||
| static const int nDets = 16; | ||
| //! Number of ASICs per detector | ||
| static const int nASICs = 4; | ||
| static const int nASICs = 6; | ||
|
|
||
| //! Stores dead time for each ASIC | ||
| vector<vector<double>> m_ASICDeadTime; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,4 @@ | ||
| CoincidenceWindow (s); DeadtimePerStrip (s); delayAfter1 (s); delayAfter2 (s) | ||
| 1.4e-6 1e-6 0.2e-6 0.2e-6 | ||
| CoincidenceWindow (s); StripDeadtimePerStrip (s); delayAfter1 (s); delayAfter2 (s) | ||
| 1.4e-6 1e-6 0.2e-6 0.2e-6 | ||
| ShieldDeadtimePerStrip (s); ShieldVetoWindow (s); ShieldPulseDuration (s); ShieldDelayBefore (s); ShieldDelayAfter (s) | ||
| 1e-6 1.5e-6 1.7e-6 0.1e-6 0.4e-6 | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we expect any of these parameters to change detector by ASIC by ASIC or anything? Or are these parameters which will be valid for all GeDs and all shields? |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -156,12 +156,13 @@ bool MModuleDEESMEX::AnalyzeEvent(MReadOutAssembly* Event) | |
| m_ShieldTrigger.Clear(); | ||
| m_ShieldTrigger.AnalyzeEvent(Event); | ||
| if (m_ShieldTrigger.HasVeto() == true) { | ||
| Event->SetShieldVeto(true); | ||
| if (m_ShieldTrigger.GetDeadTimeEnd() > m_DeadTimeEnd) { | ||
| m_DeadTimeEnd = m_ShieldTrigger.GetDeadTimeEnd(); | ||
| } | ||
|
|
||
| // Clean up | ||
|
|
||
| Event->SetAnalysisProgress(MAssembly::c_DetectorEffectsEngine); | ||
| return true; | ||
| } else if (m_ShieldTrigger.HasTrigger() == true) { // = energy read out | ||
|
|
@@ -192,8 +193,7 @@ bool MModuleDEESMEX::AnalyzeEvent(MReadOutAssembly* Event) | |
| if (m_StripTrigger.GetDeadTimeEnd() > m_DeadTimeEnd) { | ||
| m_DeadTimeEnd = m_StripTrigger.GetDeadTimeEnd(); | ||
| } | ||
| // Clean up | ||
|
|
||
| Event->SetGuardRingVeto(true); // <-- mark the event so EventSaver can filter it | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's not clear to me that this "m_StripTrigger.HasVeto()" corresponds to a GuardRingVeto vs a Shield Veto. Can we improve the variable names to clarify it's a shield veto or GR veto. "HasVeto" should encompass both veto cases, and we should probably introduce a HasShieldVeto and HasGuardRingVeto variable. See, for example, the veto variable names in MReadOutAssembly: |
||
| Event->SetAnalysisProgress(MAssembly::c_DetectorEffectsEngine); | ||
| return true; | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -132,7 +132,8 @@ bool MSubModuleDEEIntake::AnalyzeEvent(MReadOutAssembly* Event) | |
| double DetectorDepth = Shape->GetSizeZ(); | ||
|
|
||
| MString DetectorName = Detector->GetName(); | ||
| if (DetectorName.BeginsWith("GeD") == true) { | ||
| if (DetectorName.BeginsWith("GeD") == true || DetectorName.BeginsWith("GuardRing") == true) { | ||
| DetectorName.RemoveAllInPlace("GuardRingDetector_GeD_"); // Remove prefix GuardRing if existent | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just so I understand. We're checking for GuardRing here because the Geometry volume we're using in the DEE has the guard ring and the GeD as separate volumes. But the simulation has them all as one solid volume. Excluding this "GuardRingDetector_GeD_" here would exclude any hits that are within the GR volume. But we're not trying to distinguish Guardring hits here, that only comes after the charge transport, so if there is a simulated hit that is within the GuardRing volume in the Nuclearizer mass model, then it gets added as a regular hit in the detector # that precedes GuardRingDetector_GeD_. Right? |
||
| DetectorName.RemoveAllInPlace("GeD_"); // The number after GeD is the COSI detector ID | ||
| int DetectorID = DetectorName.ToInt(); | ||
|
|
||
|
|
@@ -198,29 +199,6 @@ bool MSubModuleDEEIntake::AnalyzeEvent(MReadOutAssembly* Event) | |
| return false; | ||
| } | ||
|
|
||
| // int DetectorID = -1; | ||
| // if (Tokens[1] == "X0") { | ||
| // DetectorID = 0; | ||
| // } | ||
| // else if (Tokens[1] == "X1") { | ||
| // DetectorID = 1; | ||
| // } | ||
| // else if (Tokens[1] == "Y0") { | ||
| // DetectorID = 2; | ||
| // } | ||
| // else if (Tokens[1] == "Y1") { | ||
| // DetectorID = 3; | ||
| // } | ||
| // else if (Tokens[1] == "Z0") { | ||
| // DetectorID = 4; | ||
| // } | ||
| // else if (Tokens[1] == "Z1") { | ||
| // DetectorID = 5; | ||
| // } | ||
| // else { | ||
| // cerr << "ERROR: Detector name does not correspond to any panel " << Tokens[1] << endl; | ||
| // return false; | ||
| // } | ||
| MString DetectorID = Tokens[1]; | ||
| int CrystalID = Tokens[2].ToInt(); | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -65,11 +65,9 @@ MSubModuleShieldTrigger::MSubModuleShieldTrigger() : MSubModule() | |
| m_ShieldDelayBefore = 0.1e-6; | ||
| m_ShieldDelayAfter = 0.4e-6; | ||
| m_ShieldVetoWindowSize = 1.5e-6; | ||
| m_ASICDeadTimePerChannel = 0.0; | ||
| m_ShieldVetoTime = 0.0; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do we no longer need m_ShieldVetoTime? Is this redundant with m_ShieldVetoWindowSize or m_ASICDeadTimePerChannel? |
||
| m_ASICDeadTimePerChannel = 1e-6; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't these variables come from the ParseDeadtimeFiles function? Is this just a placeholder for now? |
||
|
|
||
| m_NumShieldHitCounts = 0; | ||
| m_NumShieldVetoCounts = 0; | ||
| m_NumBGOHitsErased = 0; | ||
|
|
||
| m_FirstTime = std::numeric_limits<double>::max(); | ||
|
|
@@ -173,24 +171,21 @@ double MSubModuleShieldTrigger::CalculateASICDeadtime(vector<int> CrystalIDs) | |
| return deadtime; | ||
| } | ||
|
|
||
|
|
||
| //////////////////////////////////////////////////////////////////////////////// | ||
|
|
||
|
|
||
| bool MSubModuleShieldTrigger::ProcessShieldHits(MReadOutAssembly* Event) | ||
| { | ||
| // Process shield crystal hits to determine veto status | ||
|
|
||
| m_EventTime = Event->GetTime().GetAsSeconds(); | ||
|
|
||
| // Track which GeD detectors got hit (for later deadtime update) | ||
| list<MDEEStripHit>& LVHits = Event->GetDEEStripHitLVListReference(); | ||
| for (const MDEEStripHit& Hit : LVHits) { | ||
| int DetID = Hit.m_ROE.GetDetectorID(); | ||
| if (DetID >= 0 && DetID < nDets) { | ||
| m_DetectorsHitForShieldVeto[DetID] = 1; | ||
| } | ||
| } | ||
| // // Track which GeD detectors got hit (for later deadtime update) | ||
| // list<MDEEStripHit>& LVHits = Event->GetDEEStripHitLVListReference(); | ||
| // for (const MDEEStripHit& Hit : LVHits) { | ||
| // int DetID = Hit.m_ROE.GetDetectorID(); | ||
| // if (DetID >= 0 && DetID < nDets) { | ||
| // m_DetectorsHitForShieldVeto[DetID] = 1; | ||
| // } | ||
| // } | ||
|
Comment on lines
+181
to
+188
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why was this commented? Do you plan on adding it back later (in a modified form)?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nope, I will remove this permanently. This was leftover from old balloon code. |
||
|
|
||
| // Process shield crystal hits | ||
| list<MDEECrystalHit>& CrystalHits = Event->GetDEECrystalHitListReference(); | ||
|
|
@@ -232,22 +227,17 @@ bool MSubModuleShieldTrigger::ProcessShieldHits(MReadOutAssembly* Event) | |
| continue; | ||
| } | ||
|
|
||
| // cout << m_ShieldLastHitTime[ShieldDetGroup] + m_ShieldDeadtime[ShieldDetGroup] << " " << m_EventTime << endl; | ||
| // Check deadtime conditions | ||
| if (m_EventTime > (m_ShieldLastHitTime[ShieldDetGroup] + m_ShieldDeadtime[ShieldDetGroup])) { | ||
| // Event occurred after deadtime - start new veto window | ||
| m_ShieldHitCrystalID[ShieldDetGroup].clear(); | ||
| m_ShieldLastHitTime[ShieldDetGroup] = m_EventTime; | ||
| m_ShieldVetoTime = m_EventTime; | ||
| m_ShieldHitCrystalID[ShieldDetGroup].push_back(CrystalID); | ||
| m_HasVeto = true; | ||
| m_TotalShieldDeadtime[ShieldDetGroup] += m_ShieldDeadtime[ShieldDetGroup]; | ||
| } | ||
| else if (m_EventTime <= (m_ShieldLastHitTime[ShieldDetGroup] + m_ShieldDelayBefore)) { | ||
| // Event occurred within coincidence window - add to existing veto | ||
| m_ShieldVetoTime = m_EventTime; | ||
| m_ShieldHitCrystalID[ShieldDetGroup].push_back(CrystalID); | ||
| m_HasVeto = true; | ||
| } | ||
| else { | ||
| // Event occurred within deadtime | ||
|
|
@@ -259,18 +249,7 @@ bool MSubModuleShieldTrigger::ProcessShieldHits(MReadOutAssembly* Event) | |
|
|
||
| // Calculate deadtime for each panel group after processing all hits | ||
| for (int group = 0; group < nShieldPanels; group++) { | ||
| if (!m_IsShieldDead) { | ||
| m_ShieldDeadtime[group] = CalculateASICDeadtime(m_ShieldHitCrystalID[group]); | ||
| } | ||
| } | ||
|
|
||
| // Check if event is within veto window | ||
| if ((m_EventTime <= (m_ShieldVetoTime + m_ShieldVetoWindowSize)) && | ||
| (m_EventTime >= m_ShieldVetoTime)) { | ||
| m_HasVeto = true; | ||
| if (Event->GetSimulatedEvent() != nullptr) { | ||
| m_NumShieldVetoCounts += Event->GetSimulatedEvent()->GetNHTs(); | ||
| } | ||
| } | ||
|
|
||
| return true; | ||
|
|
@@ -283,21 +262,34 @@ bool MSubModuleShieldTrigger::ProcessShieldHits(MReadOutAssembly* Event) | |
| bool MSubModuleShieldTrigger::ParseDeadtimeFile() | ||
| { | ||
| // Read in deadtime parameters file | ||
| // Format: StripCoincidenceWindow ASICDeadTimePerChannel StripDelayAfter1 StripDelayAfter2 | ||
| // Format: | ||
| // Row 1: strip trigger header | ||
| // Row 2: strip trigger parameters | ||
| // Row 3: shield trigger header | ||
| // Row 4: shield trigger parameters | ||
|
|
||
| MParser Parser; | ||
| if (Parser.Open(m_DeadtimeFileName) == false) { | ||
| cout << m_Name << ": Unable to open deadtime parameters file: " << m_DeadtimeFileName << endl; | ||
| return false; | ||
| } | ||
|
|
||
| if (Parser.GetNLines() < 2) { | ||
| if (Parser.GetNLines() < 4) { | ||
| cout << m_Name << ": Deadtime file does not have enough data" << endl; | ||
| return false; | ||
| } | ||
|
|
||
| // We only need the ASICDeadTimePerChannel (second value) for shield | ||
| m_ASICDeadTimePerChannel = Parser.GetTokenizerAt(1)->GetTokenAtAsDouble(1); | ||
| MTokenizer* ShieldTokenizer = Parser.GetTokenizerAt(3); | ||
| if (ShieldTokenizer->GetNTokens() < 5) { | ||
| cout << m_Name << ": Shield deadtime row does not have enough data" << endl; | ||
| return false; | ||
| } | ||
|
|
||
| m_ASICDeadTimePerChannel = ShieldTokenizer->GetTokenAtAsDouble(0); | ||
| m_ShieldVetoWindowSize = ShieldTokenizer->GetTokenAtAsDouble(1); | ||
| m_ShieldPulseDuration = ShieldTokenizer->GetTokenAtAsDouble(2); | ||
| m_ShieldDelayBefore = ShieldTokenizer->GetTokenAtAsDouble(3); | ||
| m_ShieldDelayAfter = ShieldTokenizer->GetTokenAtAsDouble(4); | ||
|
|
||
| return true; | ||
| } | ||
|
|
@@ -314,16 +306,24 @@ bool MSubModuleShieldTrigger::AnalyzeEvent(MReadOutAssembly* Event) | |
| m_HasVeto = false; | ||
| m_IsShieldDead = false; | ||
|
|
||
| m_EventTime = Event->GetTime().GetAsSeconds(); | ||
|
|
||
| // First: veto based on shield state from previous events | ||
| for (int group = 0; group < nShieldPanels; ++group) { | ||
| if (m_EventTime >= m_ShieldLastHitTime[group] && | ||
| m_EventTime <= m_ShieldLastHitTime[group] + m_ShieldVetoWindowSize) { | ||
| m_HasVeto = true; | ||
| } | ||
| } | ||
|
|
||
| // Process shield hits and check for veto conditions | ||
| ProcessShieldHits(Event); | ||
|
|
||
| // Update time tracking for statistics | ||
| double eventTime = Event->GetTime().GetAsSeconds(); | ||
| if (eventTime < m_FirstTime) { | ||
| m_FirstTime = eventTime; | ||
| if (m_EventTime < m_FirstTime) { | ||
| m_FirstTime = m_EventTime; | ||
| } | ||
| if (eventTime > m_LastTime) { | ||
| m_LastTime = eventTime; | ||
| if (m_EventTime > m_LastTime) { | ||
| m_LastTime = m_EventTime; | ||
| } | ||
|
|
||
| // If vetoed, set the dead time end | ||
|
|
@@ -370,7 +370,6 @@ void MSubModuleShieldTrigger::Finalize() | |
| } | ||
|
|
||
| cout << "BGO hits erased due to BGO being dead: " << m_NumBGOHitsErased << endl; | ||
| cout << "Shield vetoes: " << m_NumShieldVetoCounts << endl; | ||
|
|
||
| if (simTime > 0) { | ||
| double rateAfterDT = (m_NumShieldHitCounts - m_NumBGOHitsErased) / simTime; | ||
|
|
@@ -411,4 +410,4 @@ MXmlNode* MSubModuleShieldTrigger::CreateXmlConfiguration(MXmlNode* Node) | |
|
|
||
|
|
||
| // MSubModuleShieldTrigger.cxx: the end... | ||
| //////////////////////////////////////////////////////////////////////////////// | ||
| //////////////////////////////////////////////////////////////////////////////// | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we not want to track the number of vetos with this counter?