Skip to content

Add unpolarized unbinned source injector capability [Yong2Sheng's]#499

Open
israelmcmc wants to merge 1 commit intocositools:developfrom
Yong2Sheng:unbinned_source_injector
Open

Add unpolarized unbinned source injector capability [Yong2Sheng's]#499
israelmcmc wants to merge 1 commit intocositools:developfrom
Yong2Sheng:unbinned_source_injector

Conversation

@israelmcmc
Copy link
Collaborator

I'm bringing @Yong2Sheng from my fork to develop, now that the interfaces branch is merged.

Summary

This PR introduces an initial implementation for unpolarized unbinned continuum point source injector in the spacecraft frame. It follows the existing line injector workflow, but with additional steps to (1) compute the integrated detected rate across an energy band and (2) sample detected photon energies across that band.

Compute incident photons and simulate events

1) Define a continuum spectrum (differential photon flux)

A power-law spectrum is used as the working example in the tutorial:

$$S(E)=K\left(\frac{E}{\mathrm{piv}}\right)^{\mathrm{index}}, \qquad [S(E)] = \frac{\mathrm{ph}}{\mathrm{cm^2}\times\mathrm{s}\times\mathrm{keV}} $$

where $K$ is the normalization (differential flux at the pivot energy $\mathrm{piv}$).

2) Convolve the spectrum with effective area

The detected count-rate density is

$$ w(E) \equiv S(E)\times A_{\text{eff}}(E), \qquad [w(E)] = \frac{\mathrm{ph}}{\mathrm{s}\times\mathrm{keV}}. $$

3) Integrate $w(E)$ to get the total detected rate and total counts

The integrated detected photon rate is

$$ I_0 = \int_{E_\mathrm{min}}^{E_\mathrm{max}} w(E) dE, \qquad [I_0] = \frac{\mathrm{ph}}{\mathrm{s}}. $$

In practice, the spectrum might not be analytical. And the effective area is also usually not analytical as well. So we do not perform the integral directly. Instead, we will use a very fine energy grid to obtain the integral by trapezoids.

The expected detected counts is

$$ \mu = T\times I_0, $$

and the realized detected counts are sampled as

$$ N \sim \mathrm{Poisson}(\mu). $$

4) Build an inverse-CDF sampler to draw detected photon energies

  • Construct a discrete CDF from $w(E)$ on the energy grid via cumulative trapezoidal integration, and normalized it by $I_0$ to $[0,1]$.
  • Draw a uniform distribution from [0,1): $u \sim \mathrm{Unif}(0,1)$.
  • Apply inverse transform sampling: $E_i = CDF^{-1}(u)$, where $CDF^{-1}$ is implemented using scipy.interpolate.interp1d with linear interpolation.

5) Simulate each sampled energy

Feed the sampled photon energies (and their multiplicities, although they should show up only once) into UnpolarizedIdealComptonIRF.random_events(...) to produce the event list.

Implementation notes

  1. A new class RandomEventDataFromContinuumInSCFrame is responsible for continuum injection.
  2. For performance and clarity, I cache the following intermediates with @cached_property:
    • energy_grid
    • unpolarized_aeff
    • unpol_counts
    • incident_photons
  3. A structured return container for detected-count (unpol_counts) bookkeeping:
    • UnpolCountsSummary(rate_density, rate, total_expected_counts)

What is not included yet

  • Polarization handling for the continuum branch (this PR is unpolarized only).

@codecov
Copy link

codecov bot commented Mar 9, 2026

Codecov Report

❌ Patch coverage is 0% with 81 lines in your changes missing coverage. Please review.
✅ Project coverage is 70.17%. Comparing base (6765236) to head (b41310a).

Files with missing lines Patch % Lines
cosipy/response/ideal_response.py 0.00% 81 Missing ⚠️

❌ Your patch check has failed because the patch coverage (0.00%) is below the target coverage (100.00%). You can increase the patch coverage or adjust the target coverage.

Files with missing lines Coverage Δ
cosipy/response/ideal_response.py 0.00% <0.00%> (ø)

... and 3 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@Yong2Sheng
Copy link
Contributor

I will add the unit tests after the changes have been reviewed and approved. I’d like to avoid adding them too early, since they may need to be updated if the code changes during review.

@israelmcmc
Copy link
Collaborator Author

See my comment in #528

This is also related to #499: if the user passes a UnbinnedThreeMLModelFoldingInterface, we can inject event data right from the same class.

It's fine for now, but eventually this capability should be moved to the SourceInjector class.

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

Labels

None yet

Projects

Status: Under review

Development

Successfully merging this pull request may close these issues.

3 participants