Skip to content

det_align: GEM hits projected to HyCal z twice in Mott residuals; Moller phi coplanarity cut is one-sided #4

Description

@Chao1009

Where

What happens

  1. GEM points are projected twice. The residual loop iterates with auto& event and rescales GEM_x/GEM_y to the HyCal plane in place (*= HC_z / GEM_z[det]). This happens once in the all-4-matched block, then again in the {0,2} block and again in the {1,3} block. GEM_z is never updated, so an event with all four chambers matched ends up with the points scaled by (HC_z/GEM_z)^2 instead of HC_z/GEM_z. Events where only one pair matches are handled correctly.

    • With the default PRad-II survey (database/runinfo/general.json: HyCal z = 6265.887, GEM z = 5813.831 / 5853.713 / 5411.839 / 5456.658 mm), the extra factor is about 1.078 / 1.070 / 1.158 / 1.148 for GEM0..3. For the X17 geometry it is about 1.065 / 1.059 / 1.130 / 1.122.
    • Example: a raw GEM0 hit at y = 100 mm should project to 107.8 mm, but it is filled as 116.2 mm. That is 8.4 mm off, against a histogram range of ±20 mm.
    • For a perfectly aligned setup, the left-layer residual GEM_x[0] - GEM_x[2] from these events becomes ≈ (1.078 − 1.158)·x ≈ −0.08·x instead of 0. The right-layer residual becomes ≈ −0.078·x.
    • Affected histograms: h1_deltaX/Y_gem_hycal{0..3}, h1_deltaX/Y_gem_layer_left/right and h2_deltaX_vs_deltaY_gem_left/right. The up/down histograms filled inside the all-4 block are correct.
    • GEM_layer_left_* and GEM_layer_right_* are applied to gem_x/gem_y of GEM0 and GEM1 in the output run config (L558-L563). deltaX/Y_gem_hycal_* are written to the alignment summary.
  2. The Moller coplanarity cut is one-sided.

    float phi1 = std::atan2(ev.cl_y[0], ev.cl_x[0]) * 180.0 / M_PI;
    float phi2 = std::atan2(ev.cl_y[1], ev.cl_x[1]) * 180.0 / M_PI;
    ...
    if (std::abs(phi1 - phi2) -180.0 > 8.0) continue;

    This only rejects pairs with |Δφ| > 188°. Every pair with |Δφ| ≤ 188° passes, including same-side pairs (for example φ1 = 30°, φ2 = 20°). Only the energy cuts are left to reject them. The selected Moller sample feeds the HyCal/GEM Moller-center, z-distance and HyCal−GEM phi-difference fits. Those fits set target_x/y, hycal_z, gem_z and gem_tilt_z in the output run config.

Evidence

for (auto& event : all_mott_events) {
    if (event.match[0] && event.match[1] && event.match[2] && event.match[3]) {
        for (int det = 0; det < 4; ++det) {
            float scale = event.HC_z / event.GEM_z[det];
            event.GEM_x[det] *= scale;   // 1st projection
            event.GEM_y[det] *= scale;
        }
        ...
    }
    if (event.match[0] && event.match[2]) {
        for (int det : {0, 2}) {
            float scale = event.HC_z / event.GEM_z[det];
            event.GEM_x[det] *= scale;   // 2nd projection of the same event
            event.GEM_y[det] *= scale;
            h1_deltaX_gem_hycal[det]->Fill(event.GEM_x[det] - event.HC_x);
            ...

Other tools in the repo already use the two-sided phi cut: analysis/tools/leakage_correction_check.cpp:313 (std::abs(std::fabs(phi1 - phi2) - 180.f)) and analysis/tools/quick_check.cpp:935.

Suggested fix

  • Project each matched GEM point once at the top of the loop, then use the projected values in all three blocks. Guard with match[det], because unmatched entries have GEM_z = 0.
    for (auto& event : all_mott_events) {
        for (int det = 0; det < 4; ++det) {
            if (!event.match[det]) continue;
            const float scale = event.HC_z / event.GEM_z[det];
            event.GEM_x[det] *= scale;
            event.GEM_y[det] *= scale;
        }
        // all-4 / {0,2} / {1,3} blocks: fill only, no further scaling
    }
  • Make the phi cut two-sided:
    if (std::abs(std::abs(phi1 - phi2) - 180.0) > 8.0) continue;
  • Both fixes change det_align outputs (the iterated run config and the summary), so earlier alignment iterations should be re-run.

Status

Still present on the dedup-refactor branch. The scaling there is a project(det) lambda that is still called in all three blocks, and the phi cut is unchanged. Both were left alone so the refactor stays output-identical.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions