Skip to content

Controller output features and integration fixes#112

Closed
austinschneider wants to merge 1 commit into
feat/hnl-3body-samplingfrom
feat/controller-output
Closed

Controller output features and integration fixes#112
austinschneider wants to merge 1 commit into
feat/hnl-3body-samplingfrom
feat/controller-output

Conversation

@austinschneider

Copy link
Copy Markdown
Collaborator

Stack: PR 14 of 14

This PR is part of a 14-PR stack decomposing dev/HNL_DIS into reviewable chunks.

  • Base: feat/hnl-3body-sampling
  • Head: feat/controller-output

Merge order: feat/hnl-3body-sampling should land before this PR.

Squashed contents

Squashed diff for paths:

  • python/SIREN_Controller.py
  • projects/injection/private/Weighter.cxx
  • projects/injection/public/SIREN/injection/Weighter.h
  • projects/injection/private/pybindings/injection.cxx
  • cmake/Packages/CFITSIO.cmake
  • vendor/googletest

Source commits on dev/HNL_DIS_clean that contributed:
088b1cd (Nicholas Kamp): move around the HNL DIS fits files
0a9c9aa (Nicholas Kamp): ability to save interaction probabilities for each process
0c7ad93 (Nicholas Kamp): support sphere volume distributions in python interface
197bf14 (Nicholas Kamp): fixing build errors from the merge
1d68f30 (Nicholas Kamp): fix runtime errors on HNL generation related to particle types
4f113a1 (Nicholas Kamp): add survival probability function
521695f (Nicholas Kamp): fix issues with 2D tabular integral calculation, sampling errors with very short decay lengths, DarkNews errors, and kinematic erros in Dipole portal HNL DIS
631c12a (Nicholas Kamp): add ability to save interaction parameters to output file
82bcb80 (Nicholas Kamp): fix error in loading mat/det files
ac0ce24 (Nicholas Kamp): changes to facilitate hadronic and W/Z HNL decays
cf24f42 (Nicholas Kamp): add secondary fid vol flag in controller
da5f6b2 (Nicholas Kamp): detector changes, functionality to save initial position of interaction_record, and fix to HNLDISFromSpline.cxx
f183191 (Nicholas Kamp): more complex logic for adding darknews interactions, fix some errors in SIREN_DarkNews

Notes

  • This branch is the squashed cumulative diff of the listed source commits. Per-commit history is browsable on dev/HNL_DIS_clean.
  • Large .fits data files have been removed from the branch and are packaged separately.

Squashed diff for paths:
  - python/SIREN_Controller.py
  - projects/injection/private/Weighter.cxx
  - projects/injection/public/SIREN/injection/Weighter.h
  - projects/injection/private/pybindings/injection.cxx
  - cmake/Packages/CFITSIO.cmake
  - vendor/googletest

Source commits on dev/HNL_DIS_clean that contributed:
  088b1cd (Nicholas Kamp): move around the HNL DIS fits files
  0a9c9aa (Nicholas Kamp): ability to save interaction probabilities for each process
  0c7ad93 (Nicholas Kamp): support sphere volume distributions in python interface
  197bf14 (Nicholas Kamp): fixing build errors from the merge
  1d68f30 (Nicholas Kamp): fix runtime errors on HNL generation related to particle types
  4f113a1 (Nicholas Kamp): add survival probability function
  521695f (Nicholas Kamp): fix issues with 2D tabular integral calculation, sampling errors with very short decay lengths, DarkNews errors, and kinematic erros in Dipole portal HNL DIS
  631c12a (Nicholas Kamp): add ability to save interaction parameters to output file
  82bcb80 (Nicholas Kamp): fix error in loading mat/det files
  ac0ce24 (Nicholas Kamp): changes to facilitate hadronic and W/Z HNL decays
  cf24f42 (Nicholas Kamp): add secondary fid vol flag in controller
  da5f6b2 (Nicholas Kamp): detector changes, functionality to save initial position of interaction_record, and fix to HNLDISFromSpline.cxx
  f183191 (Nicholas Kamp): more complex logic for adding darknews interactions, fix some errors in SIREN_DarkNews
Copilot AI review requested due to automatic review settings April 28, 2026 04:29
@austinschneider austinschneider force-pushed the feat/hnl-3body-sampling branch from 542e789 to ad12640 Compare April 28, 2026 04:34
@austinschneider austinschneider force-pushed the feat/controller-output branch from 008a996 to 7e97b68 Compare April 28, 2026 04:34

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds controller-side output toggles and new weighter APIs to expose interaction/survival probabilities, alongside integration/build fixes for model-file handling and CFITSIO discovery.

Changes:

  • Extend SIREN_Controller to support explicit detector/material model paths and to optionally save interaction probabilities/parameters/survival probabilities.
  • Add Weighter C++ APIs (and pybindings) to retrieve per-interaction probabilities and survival probabilities.
  • Improve CFITSIO CMake discovery by searching CMAKE_PREFIX_PATH.

Reviewed changes

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

Show a summary per file
File Description
python/SIREN_Controller.py Adds new controller options for model files, fiducial restrictions for secondaries, and richer event output fields.
projects/injection/public/SIREN/injection/Weighter.h Declares new probability accessors on ProcessWeighter/Weighter.
projects/injection/private/Weighter.cxx Implements per-interaction probability and survival probability extraction.
projects/injection/private/pybindings/injection.cxx Exposes the new Weighter APIs to Python via pybind11.
cmake/Packages/CFITSIO.cmake Extends CFITSIO search paths to include CMAKE_PREFIX_PATH.
vendor/googletest Vendored dependency updated (not shown in diff excerpt).

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

Comment on lines +75 to +76
print("Must provide either an experiment name or both a detector model file and materials model file. Exiting")
exit(0)

Copilot AI Apr 28, 2026

Copy link

Choose a reason for hiding this comment

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

exit(0) reports success even though initialization failed, which can silently mask errors in calling code and CI. Prefer raising a Python exception (e.g., ValueError) for library code; if this is truly CLI-only behavior, use a non-zero exit code (e.g., sys.exit(1)).

Suggested change
print("Must provide either an experiment name or both a detector model file and materials model file. Exiting")
exit(0)
raise ValueError("Must provide either an experiment name or both a detector model file and materials model file.")

Copilot uses AI. Check for mistakes.
if self.primary_physical_process.primary_type == _dataclasses.Particle.ParticleType.unknown:
self.primary_physical_process.primary_type = primary_interaction_collection.GetPrimaryType()
else:
assert(self.primary_injection_process.primary_type == primary_interaction_collection.GetPrimaryType())

Copilot AI Apr 28, 2026

Copy link

Choose a reason for hiding this comment

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

The assertion in the physical branch compares against self.primary_injection_process.primary_type rather than self.primary_physical_process.primary_type. This can incorrectly pass/fail depending on prior injection configuration and can hide a mismatch in the physical process type. The assert should check the physical process’ primary_type.

Suggested change
assert(self.primary_injection_process.primary_type == primary_interaction_collection.GetPrimaryType())
assert(self.primary_physical_process.primary_type == primary_interaction_collection.GetPrimaryType())

Copilot uses AI. Check for mistakes.
Comment on lines +283 to 293
for secondary_injection_process in self.secondary_injection_processes:
if secondary_injection_process.primary_type == secondary_type:
inj_sec_defined = True
for secondary_physical_process in self.secondary_physical_processes:
if secondary_physical_process.primary_type == secondary_type:
phys_sec_defined = True

secondary_injection_process = _injection.SecondaryInjectionProcess()
secondary_physical_process = _injection.PhysicalProcess()
secondary_injection_process.primary_type = secondary_type
secondary_physical_process.primary_type = secondary_type

Copilot AI Apr 28, 2026

Copy link

Choose a reason for hiding this comment

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

When a secondary process for secondary_type already exists, this code still creates new secondary_injection_process/secondary_physical_process instances, adds distributions to those new instances, and then discards them (because they aren’t appended). That means existing processes won’t receive the intended distributions/updates. Instead, locate and reuse the existing process objects when *_sec_defined is true; only create new ones when missing.

Copilot uses AI. Check for mistakes.
Comment on lines +305 to +306
if not inj_sec_defined: self.secondary_injection_processes.append(secondary_injection_process)
if not phys_sec_defined: self.secondary_physical_processes.append(secondary_physical_process)

Copilot AI Apr 28, 2026

Copy link

Choose a reason for hiding this comment

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

When a secondary process for secondary_type already exists, this code still creates new secondary_injection_process/secondary_physical_process instances, adds distributions to those new instances, and then discards them (because they aren’t appended). That means existing processes won’t receive the intended distributions/updates. Instead, locate and reuse the existing process objects when *_sec_defined is true; only create new ones when missing.

Copilot uses AI. Check for mistakes.
Comment on lines +387 to +395
if type(geo)==_geometry.Cylinder:
cylinder = _geometry.Cylinder(det_placement,geo.Radius,geo.InnerRadius,geo.Z)
return _distributions.CylinderVolumePositionDistribution(cylinder)
elif type(geo)==_geometry.Sphere:
sphere = _geometry.Sphere(det_placement,geo.Radius,geo.InnerRadius)
return _distributions.SphereVolumePositionDistribution(sphere)
else:
print("Geometry type %s not supported for position distribution. Exiting"%str(type(geo)))
exit(0)

Copilot AI Apr 28, 2026

Copy link

Choose a reason for hiding this comment

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

Using type(x) == SomeType prevents subclasses/proxies from being recognized and is generally less robust than isinstance. Also, exit(0) again signals success on an error path; prefer raising NotImplementedError/ValueError so callers can handle unsupported geometry types programmatically.

Copilot uses AI. Check for mistakes.
std::tuple<siren::math::Vector3D, siren::math::Vector3D> bounds;
if(datum->depth() == 0) {
std::get<0>(bounds) = datum->record.primary_initial_position; // start location
std::get<1>(bounds) = std::get<0>(injectors[i_inj]->PrimaryInjectionBounds(datum->record)); // start of injection bounds

Copilot AI Apr 28, 2026

Copy link

Choose a reason for hiding this comment

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

i_inj is used to index injectors / *_weighters / maps without any bounds checking, which can cause undefined behavior (crash) if Python passes an invalid injector index. Additionally, catching std::out_of_range and returning {} after printing to stdout makes failures silent for Python callers. Validate i_inj up front and raise an exception (so pybind can translate it), or at minimum return an error in a way that the Python layer can detect reliably.

Copilot uses AI. Check for mistakes.
Comment on lines +180 to +184
survival_probs.push_back(1 - secondary_process_weighter_maps[i_inj].at(datum->record.signature.primary_type)->InteractionProbability(bounds, datum->record));
} catch(const std::out_of_range& oor) {
std::cout << "Out of Range error: " << oor.what() << '\n';
return {};
}

Copilot AI Apr 28, 2026

Copy link

Choose a reason for hiding this comment

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

i_inj is used to index injectors / *_weighters / maps without any bounds checking, which can cause undefined behavior (crash) if Python passes an invalid injector index. Additionally, catching std::out_of_range and returning {} after printing to stdout makes failures silent for Python callers. Validate i_inj up front and raise an exception (so pybind can translate it), or at minimum return an error in a way that the Python layer can detect reliably.

Copilot uses AI. Check for mistakes.
for secondary_type, decay_list in secondary_decays.items():
# Define a sedcondary injection distribution

# Define a sedcondary injection distribution if necessary

Copilot AI Apr 28, 2026

Copy link

Choose a reason for hiding this comment

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

Correct typo in comment: 'sedcondary' → 'secondary'.

Suggested change
# Define a sedcondary injection distribution if necessary
# Define a secondary injection distribution if necessary

Copilot uses AI. Check for mistakes.
record = _dataclasses.InteractionRecord()
record.signature.primary_type = sec_inj.primary_type
found_collection = False
# Loop through possible seconday cross sections

Copilot AI Apr 28, 2026

Copy link

Choose a reason for hiding this comment

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

Correct typo in comment: 'seconday' → 'secondary'.

Suggested change
# Loop through possible seconday cross sections
# Loop through possible secondary cross sections

Copilot uses AI. Check for mistakes.
// Returns the vector of interaction physical probabilities for each process
// Since we are concerned only with the physical probability, we use the first injector since physical processes are the same for all injectors
// HOWEVER the injection bounds will change based on the injector
// so, we allow the user to specify which injector they are interseted in

Copilot AI Apr 28, 2026

Copy link

Choose a reason for hiding this comment

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

Correct typo in comment: 'interseted' → 'interested'.

Suggested change
// so, we allow the user to specify which injector they are interseted in
// so, we allow the user to specify which injector they are interested in

Copilot uses AI. Check for mistakes.
@austinschneider

Copy link
Copy Markdown
Collaborator Author

Closing to reopen from the commit author's account so they can be added as a reviewer. Branch unchanged; will be re-linked from the new PR shortly.

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.

3 participants