Skip to content

CSG: phi-wedge support for ZSphere/Cylinder (bake startPhi/deltaPhi)#345

Open
ggalgoczi wants to merge 3 commits into
mainfrom
csg-phi-wedge-primitives
Open

CSG: phi-wedge support for ZSphere/Cylinder (bake startPhi/deltaPhi)#345
ggalgoczi wants to merge 3 commits into
mainfrom
csg-phi-wedge-primitives

Conversation

@ggalgoczi
Copy link
Copy Markdown
Contributor

@ggalgoczi ggalgoczi commented May 29, 2026

Summary

Phi-wedged G4Sphere and G4Tubs currently either abort in U4Solid or rely on a composed CSG_INTERSECTION(primitive, PhiCut) representation. That composition can lose valid hits when the first primitive candidate lies outside the wedge but a later in-wedge candidate should still be returned.

This PR bakes startPhi / deltaPhi directly into the origin-centered ZSphere and Cylinder primitives so phi clipping happens inside the primitive intersector, where candidate ordering is known.

Motivation

  • Fix the ray-leak failure mode seen with CSG_INTERSECTION(primitive, PhiCut), where a valid later hit can be dropped if the near candidate falls outside the wedge.
  • Allow phi-wedged G4Sphere / G4Tubs to convert through U4Solid instead of hitting the previous abort path.
  • Keep full-phi geometry on the existing path, with no intended behavior change for non-phi shapes.

What Changed

  • Added phi-aware primitive constructors:
    • sn::ZSphere(radius, z1, z2, startPhi, deltaPhi)
    • sn::Cylinder(radius, z1, z2, startPhi, deltaPhi)
  • Reused spare parameter slots on these origin-centered primitives to carry startPhi / deltaPhi in radians.
  • Updated csg_intersect_leaf_zsphere.h to reject sphere-surface candidates outside the phi wedge.
  • Updated csg_intersect_leaf_cylinder.h to:
    • clip curved-surface and cap candidates against the phi wedge
    • add the two radial phi-wall planes as first-class hit candidates
  • Updated U4Solid::init_Sphere_ and U4Solid::init_Tubs() to emit phi-baked primitives instead of aborting or depending on a separate PhiCut node.
  • Adjusted cylinder AABB construction so cx/cy are no longer interpreted as a geometric center when those slots carry phi parameters.
  • Added intersect_leaf_phi_wedge_test.cc regression coverage for recovered far hits, outside-wedge misses, and no-clip controls.

Behavior / Compatibility

  • deltaPhi == 0 or deltaPhi >= 2pi preserves the previous full-primitive behavior.
  • Non-phi Sphere / ZSphere / Cylinder / Tubs paths are intended to be unchanged.
  • For full spheres with a phi wedge, U4Solid now emits a phi-baked ZSphere over the full [-radius, +radius] z-range.
  • The resulting representation is simpler than CSG_INTERSECTION(primitive, PhiCut) and keeps wedge logic local to the primitive intersector.

Test Coverage

  • CSG/tests/intersect_leaf_phi_wedge_test.cc

This test covers:

  • an in-wedge hit on the primitive surface
  • the original leak regression, where the near candidate is outside the wedge but the far candidate is valid
  • a ray that stays fully outside the wedge and should miss
  • a no-clip control path to confirm unchanged full-phi behavior

Scope Note

This PR mainly covers the primitive/intersector path and the corresponding U4Solid emitters. Additional end-to-end and sliced-sphere edge-case coverage would still be useful follow-up work.

G4Sphere/G4Tubs with a phi wedge previously aborted in U4Solid. Bake the wedge into the primitive instead of composing CSG_INTERSECTION(ZSphere/Cylinder, PhiCut), which leaks rays whose origin is outside the wedge. sn::ZSphere/Cylinder gain 5-arg overloads parking startPhi/deltaPhi in the cx/cy slots; the csg_intersect_leaf_{zsphere,cylinder}.h leaves clip candidates to the wedge; U4Solid::init_Sphere_/init_Tubs emit the phi-baked primitives; CSGNode cylinder AABB no longer treats cx/cy as the centre. deltaPhi==0 (or >=2pi) => no clip, so non-phi geometry is unchanged.
@ggalgoczi ggalgoczi self-assigned this May 29, 2026
@ggalgoczi ggalgoczi added the enhancement New feature or request label May 29, 2026
@ggalgoczi ggalgoczi marked this pull request as draft May 29, 2026 14:08
…der)

Self-checking ctest for the per-primitive phi-wedge clip in
csg_intersect_leaf_{zsphere,cylinder}.h: asserts a ray whose near surface
candidate is outside the wedge still recovers the in-wedge hit (the original
CSG_INTERSECTION(prim,PhiCut) leak), and a ray crossing entirely outside the
wedge misses. Exit code is meaningful so regressions fail under ctest.
@ggalgoczi ggalgoczi marked this pull request as ready for review May 30, 2026 14:50
@ggalgoczi
Copy link
Copy Markdown
Contributor Author

@plexoos test fails because needs #344 merged first.

@plexoos
Copy link
Copy Markdown
Member

plexoos commented Jun 2, 2026

@plexoos test fails because needs #344 merged first.

I don't see anything failing in CI

@plexoos
Copy link
Copy Markdown
Member

plexoos commented Jun 2, 2026

G4Sphere/G4Tubs with a phi wedge previously aborted in U4Solid.

Could you remind me where was this happening?

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds phi-wedge support for G4Sphere/G4Tubs by baking startPhi/deltaPhi directly into the CSG_ZSPHERE / CSG_CYLINDER leaf primitives (instead of composing an intersection with a separate PhiCut), addressing previously observed ray “leaks” for wedge geometries.

Changes:

  • Add 5-arg sn::ZSphere / sn::Cylinder overloads that park startPhi/deltaPhi into the param slots formerly used for cx/cy.
  • Update U4Solid to emit phi-baked primitives for spheres and tubs.
  • Extend leaf intersection + distance logic for CSG_ZSPHERE and CSG_CYLINDER, adjust cylinder AABB handling, and add a regression test.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
u4/U4Solid.h Emits phi-baked ZSphere/Cylinder primitives instead of aborting/avoiding phi wedges.
sysrap/sn.h Adds 5-arg Cylinder/ZSphere constructors encoding startPhi/deltaPhi into params.
CSG/csg_intersect_leaf_zsphere.h Implements optional phi-wedge clipping for ZSphere leaf distance/intersection.
CSG/csg_intersect_leaf_cylinder.h Implements optional phi-wedge clipping (including wedge walls) for Cylinder leaf distance/intersection.
CSG/CSGNode.cc Updates cylinder AABB computation to ignore cx/cy now repurposed for phi params.
CSG/tests/intersect_leaf_phi_wedge_test.cc Adds CPU regression tests for baked-in phi-wedge behavior on ZSphere/Cylinder.
CSG/tests/CMakeLists.txt Registers the new regression test with CMake/ctest.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +174 to 178
if (t1sph > t_min && t1sph_ok)
t_cand = t1sph; // t1sph qualified and t1cap disabled or disqualified -> t1sph
else if (t1cap > t_min)
t_cand = t1cap; // t1cap qualifies -> t1cap
else if( t2cap > t_min ) t_cand = t2cap ; // t2cap qualifies -> t2cap
Comment on lines +32 to +33
float r_xy = sqrtf(p.x * p.x + p.y * p.y);
float d_to_edge = r_xy * fminf(dphi - deltaPhi, twoPi - dphi);
Comment on lines +249 to +250
float r_xy = sqrtf(pos.x * pos.x + pos.y * pos.y);
float d_to_edge = r_xy * fminf(dphi - deltaPhi, twoPi - dphi);
Comment on lines +152 to +162
auto phi_in_wedge = [&](float t) -> bool {
if (!has_phi_clip)
return true;
float x = O.x + t * D.x; // local-frame hit coords (O = origin − center)
float y = O.y + t * D.y;
float phi = atan2f(y, x);
const float twoPi = 2.f * M_PIf;
while (phi < startPhi) phi += twoPi;
float dphi = phi - startPhi;
return dphi <= deltaPhi;
};
Comment on lines +72 to +79
auto phi_in_wedge = [&](float xh, float yh) -> bool {
if (!has_phi_clip)
return true;
float phi = atan2f(yh, xh);
const float twoPi = 2.f * M_PIf;
while (phi < startPhi) phi += twoPi;
return (phi - startPhi) <= deltaPhi;
};
@ggalgoczi
Copy link
Copy Markdown
Contributor Author

@plexoos test fails because needs #344 merged first.

I don't see anything failing in CI

This is correct. #344 is needed for drich geometry, for specific zsphere and cylinder not needed test.

@ggalgoczi
Copy link
Copy Markdown
Contributor Author

ggalgoczi commented Jun 5, 2026

G4Sphere/G4Tubs with a phi wedge previously aborted in U4Solid.

Could you remind me where was this happening?

Two places in u4/U4Solid.h on main:
G4Sphere (init_Sphere_) — hard abort:
https://github.com/BNLNPPS/simphony/blob/main/u4/U4Solid.h#L559-L561

bool has_deltaPhi_expect = has_deltaPhi == false ;
assert( has_deltaPhi_expect );
if(!has_deltaPhi_expect) std::raise(SIGINT);

Any G4Sphere with startPhi != 0 or deltaPhi != 2π triggers assert + SIGINT.

G4Tubs (init_Tubs) — silent bug. init_Tubs() on main never reads startPhi/deltaPhi from the G4Tubs at all — it passes only (rmax, -hz, hz) to sn::Cylinder, producing a full cylinder regardless. Photons leak through where the phi boundary should be.

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

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants