3.7 DSSD 数据分析
- 根据 3.6 节分析结果,重新组织事件结构。 对每个 DSSD,先完成单片内部的 x-y 配对与 multiplicity 事例重建,再给出每个入射粒子的入射位置
(x,y)和能量e。 hit表示该探测器中在当前配对规则下重建出的粒子数,e表示分配给该粒子的重建能量。本节使用提供的完整参考重建文件 evt_16C.root,在单片相对幅度尺度上讨论层间关联。3.6 的可运行实例只覆盖一种拓扑,不是该完整参考文件的全部生成算法。
// det1
Int_t hit1;
double e1[hit1];
Int_t x1[hit1], y1[hit1];
// det2
Int_t hit2;
double e2[hit2];
Int_t x2[hit2], y2[hit2];
// det3
Int_t hit3;
double e3[hit3];
Int_t x3[hit3], y3[hit3];
%jsroot on
TFile *ipf = new TFile("./data/evt_16C.root");
if (!ipf || ipf->IsZombie()) throw std::runtime_error("无法打开输入 ROOT 文件");
TTree *tree = (TTree*)ipf->Get("tree");
if (!tree) throw std::runtime_error("输入文件中缺少 tree");
TCanvas *c1 = new TCanvas("c1","c1",900,450);
1. 相邻探测器的幅度关联
先看所有事例,再选择每层一个或两个 hit。正常穿过前层并在后层继续损失能量的粒子形成 $\Delta E$–$E$ 条带。粒子在探测器内发生反应或散射时,粒子种类、能量和路径可能改变,使事例偏离原来的条带,形成连续分布。
层间误配和电荷收集不完整也会产生带外事例。这里 Draw("e1:e2") 按数组下标组成点;后面通过位置关联检查对应关系,比较选择前后的能量图。
$\Delta E_1 : \Delta E_2$, $\Delta E_2 : \Delta E_3$
c1->SetWindowSize(1200,600);
c1->Clear();
c1->Divide(2,1);
c1->cd(1);
tree->Draw("e1:e2>>h1(1000,0,9000,1000,0,8000)","","colz");
gPad->SetLogz();
c1->cd(2);
tree->Draw("e2:e3>>h2(1000,0,9000,1000,0,8000)","","colz");
gPad->SetLogz();
c1->Draw();
一个重建粒子
选择相邻两层各有一个重建 hit 的事例,观察主粒子带及其周围的连续分布。这一选择减少了多粒子组合,但粒子在探测器内发生反应或散射后,仍可能只留下一个重建 hit。因此,下面还要检查两层位置是否相容。
c1->Clear();
c1->Divide(2,1);
c1->cd(1);
tree->Draw("e1:e2>>hh1(1000,0,9000,1000,0,8000)","hit1==1 && hit2==1","colz");
gPad->SetLogz();
c1->cd(2);
tree->Draw("e2:e3>>hh2(1000,0,9000,1000,0,8000)","hit2==1 && hit3==1","colz");
gPad->SetLogz();
c1->Draw();
每层各两个 hit
两个粒子在不同厚度的探测器内沉积能量的大小次序可能不同。因此两层各自按能量排序后,第 0 个 hit 不一定属于同一个粒子。先画未经重配的图,后面用位置检查两种对应关系。
c1->Clear();
c1->Divide(2,1);
c1->cd(1);
tree->Draw("e1:e2>>hh1(1000,0,9000,1000,0,8000)","hit1==2 && hit2==2","colz");
gPad->SetLogz();
c1->cd(2);
tree->Draw("e2:e3>>hh2(1000,0,9000,1000,0,8000)","hit2==2 && hit3==2","colz");
gPad->SetLogz();
c1->Draw();
2. 位置关联
每层一个 hit
c1->Clear();
c1->Divide(2,1);
c1->cd(1);
tree->Draw("x1-x2:y1-y2>>hx1(11,-5.5,5.5,11,-5.5,5.5)","hit1==1 && hit2==1","colz");
c1->cd(2);
tree->Draw("x2-x3:y2-y3>>hx2(11,-5.5,5.5,11,-5.5,5.5)","hit2==1 && hit3==1","colz");
c1->Draw();
两个粒子入射
c1->Clear();
c1->Divide(2,1);
c1->cd(1);
tree->Draw("x1-x2:y1-y2>>hx1(11,-5.5,5.5,11,-5.5,5.5)","hit1==2 && hit2==2","colz");
c1->cd(2);
tree->Draw("x2-x3:y2-y3>>hx2(11,-5.5,5.5,11,-5.5,5.5)","hit2==2 && hit3==2","colz");
c1->Draw();
下面用两个方向的条号差都不超过 2(整数条件 abs(Δstrip)<3)选择位置相容的候选。它能抑制一部分不相容事例,但不是“未发生反应”的充分判据;还应考虑几何对准、角度及分辨。

位置相容选择后的幅度关联
先看每层一个 hit 的样本,观察位置条件对连续分布的影响。
c1->Clear();
c1->Divide(2,1);
c1->cd(1);
tree->Draw("e1:e2>>h1(1000,0,9000,1000,0,8000)","hit1==1 && hit2==1 && abs(x1-x2)<3 && abs(y1-y2)<3","colz");
c1->cd(2);
tree->Draw("e2:e3>>h2(1000,0,9000,1000,0,8000)","hit2==1 && hit3==1 && abs(x2-x3)<3 && abs(y2-y3)<3","colz");
c1->Draw();
每层两个 hit:仍按原下标筛选
下面的数组 cut 可逐对保留当前下标下的位置相容点;它没有尝试交换配对,也没有保证一个事例的两个粒子都已匹配。
c1->Clear();
c1->Divide(2,1);
c1->cd(1);
tree->Draw("e1:e2>>h1(1000,0,8000,1000,0,8000)",
"hit1==2 && hit2==2 && abs(y1-y2)<3 && abs(x1-x2)<3",
"colz");
c1->cd(2);
tree->Draw("e2:e3>>h2(1000,0,8000,1000,0,8000)",
"hit2==2 && hit3==2 && abs(y2-y3)<3 && abs(x2-x3)<3",
"colz");
c1->Draw();
3. 明确完成两粒子的层间配对
以 DSSD2–DSSD3 为例,一个事例只有两种一一对应:直接 $(0\to0,1\to1)$ 与交换 $(0\to1,1\to0)$。每种对应都要求两个粒子在两个方向的条号差不超过 2;同一个下游 hit 不重复分配。
这个位置范围沿用前面单击样本的观察,是本例的几何相容条件。实际装置若有平移、旋转或较大入射角,应先把 strip 坐标转成实验室坐标,再按实际几何预测位置,不能把 ±2 条当作普适条件。
inline int PairLayers(const int x2[2], const int y2[2],
const int x3[2], const int y3[2], int maxDelta=2) {
bool direct=true, swapped=true;
for (int i=0; i<2; ++i) {
direct &= std::abs(x2[i]-x3[i])<=maxDelta && std::abs(y2[i]-y3[i])<=maxDelta;
swapped &= std::abs(x2[i]-x3[1-i])<=maxDelta && std::abs(y2[i]-y3[1-i])<=maxDelta;
}
if (direct && swapped) return -2;
if (direct) return 0;
if (swapped) return 1;
return -1;
}返回 0 或 1 时采用对应排列;返回 −1 表示无相容解,−2 表示两种都相容。能量接近或位置过近的粒子可能多解,不能仅为保留事例而强行指定。
运行事件循环并保留对应关系
match_dssd_layers.C 使用上面的函数,输出 matched_layers23.root。保存输入文件的行号、原 jentry、状态和 partner[i],其中 partner 是 DSSD2 第 i 个粒子对应的 DSSD3 下标。所有输入事例都保留;不属于本例 two-by-two 类的状态为 −3。
gROOT->ProcessLine(".L match_dssd_layers.C");
gROOT->ProcessLine("match_dssd_layers(2);");
TFile *fMatched=new TFile("matched_layers23.root");
if (!fMatched || fMatched->IsZombie()) throw std::runtime_error("无法打开输入 ROOT 文件");
TTree *matched=fMatched->Get<TTree>("tree");
if (!matched) throw std::runtime_error("输出文件中缺少 tree");
matched->Draw("Entry$", "status==1", "goff");
if (matched->GetSelectedRows()>0) {
Long64_t firstSwapped=Long64_t(matched->GetV1()[0]);
matched->Scan("file_entry:source_entry:status:partner:de:ee", "", "colsize=12", 1, firstSwapped);
}
Swapped example: file entry=674, original entry=2283 D2[0] (17,17) -> D3[1] (16,19) D2[1] (18,16) -> D3[0] (18,16) Input=510525, tested two-by-two=41702 Direct=7278, swapped=3585, ambiguous=623, no match=30216, saved rows=510525 ***************************************************************************************************************** * Row * Instance * file_entry * source_entry * status * partner * de * ee * ***************************************************************************************************************** * 674 * 0 * 674 * 2283 * 1 * 1 * 421.92409406 * 408.58103551 * * 674 * 1 * 674 * 2283 * 1 * 0 * 270.06379680 * 686.40996619 * *****************************************************************************************************************
用同一批事例比较配对前后
两图都只使用得到唯一几何解的事例,每个事例都画两个点。左图按原数组下标,右图使用 partner 重新对应,因此图的差别来自重配,不是额外删去某些点。其他类、多解与无解的计数已在上面单列。
TCanvas *cMatched=new TCanvas("cMatched","Layer matching comparison",1000,430);
cMatched->Divide(2,1);
cMatched->cd(1); fMatched->Get<TH2>("hBefore")->Draw("colz"); gPad->SetLogz();
cMatched->cd(2); fMatched->Get<TH2>("hAfter")->Draw("colz"); gPad->SetLogz();
cMatched->Draw();
4. 绝对能量刻度
前面的相对刻度统一的是一片 DSSD 内各条的响应;3.6 又根据 multiplicity 修正了逐条的共同 offset。它们使正反面幅度可以比较,但不同层仍各自使用相对尺度,尚不能直接把坐标写成 MeV。
绝对刻度利用能量损失规律把这些相对尺度联系到实际沉积能量。对已知粒子种类和硅厚度,计算粒子依次穿过各层时的能量损失,得到理论 $\Delta E_1$–$\Delta E_2$、$\Delta E_2$–$\Delta E_3$ 曲线;再与已经正确配对的实验条带比较,求各层刻度系数。
若每个粒子的 offset 已按参与条数修正并加和,剩余的理想线性关系可写成 $E_d=k_d a_d$,其中 $a_d$ 是第 d 层重建的相对幅度。重新采用非零截距时,应先明确它作用于单条还是整个粒子,避免重复修正。
实际比较还需要有效硅厚度、入射角及死层的影响。已知能量的峰、已知束流能量或独立的厚度测量可提供约束;增益、厚度和粒子种类不能同时任意调节后便认为获得了唯一刻度。相对幅度图可先用于寻找条带和检查关联;后续定量 PID、反应能量与不变质量重建则需要经验证的绝对刻度。
回看原始重建记录
抽查几行,确认条号、幅度与数组顺序。上面的事件循环已打印一个实际需要交换的事例及其对应位置。
// Scan 的第 4、5 参数限制输入 entry,并不是“前几个通过 cut 的事件”。
tree->Draw("Entry$", "hit2==2 && hit3==2", "goff");
if (tree->GetSelectedRows()>0) {
Long64_t firstTwo=Long64_t(tree->GetV1()[0]);
tree->Scan("x2:x3:y2:y3:int(e2):int(e3)", "", "colsize=10", 1, firstTwo);
}
***************************************************************************************************** * Row * Instance * x2 * x3 * y2 * y3 * int(e2) * int(e3) * ***************************************************************************************************** * 7 * 0 * 7 * 5 * 19 * 21 * 868 * 1445 * * 7 * 1 * 6 * 3 * 17 * 17 * 562 * 1353 * *****************************************************************************************************
5. 几何关系与能量关系共同确定粒子对应
各层按能量从高到低保存 hit,只确定了本层数组的顺序。一个粒子在相邻两层的沉积能量与粒子种类、剩余能量和层厚有关,因此各层的能量排序不一定相同。上面打印的交换配对实例显示:同下标连接并不总是同一个粒子。误配会在 $\Delta E$–$E$ 图中形成偏离正确条带的点。
几何约束:轨迹是否来自同一靶点
条号接近是本例的第一层筛选。进一步分析时,先根据每层的位置、条距和安装角度,把条号转换为实验室坐标;对每种候选排列,用靶后各层的击中位置构造粒子轨迹并反推靶点。若同一实验还记录了靶前 PPAC 径迹,就比较两个独立重建的靶上位置,选择在测量精度内相容的组合。
几何比较应考虑探测器对准、位置分辨和多重散射。偏离直线或靶点可以提示散射、反应或误配,但单一位置 cut 不能直接证明“未发生反应”。这里的参考文件未提供相配套的 PPAC 逐事件记录,因此上述靶点约束作为实际实验中的进一步方法,而不把第二章的独立数据文件与这里拼接。
能量约束:是否符合粒子的逐层能量损失
完成绝对刻度后,可比较候选组合与已知粒子的 $\Delta E$–$E$ / PID 关系:几何允许的两种组合中,哪一种同时符合各粒子在相邻层的能量损失?位置与能量应联合检验。若两粒子的位置和能量都很接近,仍可能留下多个解;保留对应关系和歧义状态,便于继续利用后续探测器或反应运动学作判断。
6. 从事例重建进入物理分析
粒子种类、各层归属、总动能和出射方向确定后,才能进一步分析反应类型、重建反应 Q 值或碎片的不变质量谱。例如,两个碎片的能量和相对夹角共同决定它们的相对能量;错误的跨层对应既会改变粒子能量,也会改变出射方向,因而可能在最终谱中制造本底甚至非物理结构。
后续物理量分析应保留本节建立的源事例编号、配对状态与能量信息,使最终谱中的异常区域能够回溯到各层信号。对应的运动学方法见不变质量重建。
