Skip to content

Conversation

@cfichtlscherer
Copy link
Contributor

Description

This pull request adds a CorrelatedSource class that enables coincident particle emissions in fixed-source simulations. This allows, for example, the simulation of Co-60 summation peaks observed in gamma detectors.

The idea is that a source can now emit multiple particles per history. A CorrelatedSource wraps several IndependentSource sub-sources that share the same spatial position and time but have independent particle types, energies, and angular distributions. The primary particle is created normally, and the coincident particles are passed directly into the secondary bank of that particle.

A per-sub-source emission probability can be set to control how often each coincident particle is created (e.g., a secondary gamma emitted only 50% of the time to represent branching ratios in decay schemes).

For tallies, each correlated particle carries its full weight. This means a single-source event can produce multiple counts in a tally, which is more intuitive than splitting the weight among correlated particles.

Example usage

  gamma1 = openmc.IndependentSource(
      energy=openmc.stats.Discrete([1.33e6], [1.0]),
      particle='photon'
  )
  gamma2 = openmc.IndependentSource(
      energy=openmc.stats.Discrete([1.17e6], [1.0]),
      particle='photon'
  )

  source = openmc.CorrelatedSource(
      space=openmc.stats.Point((0, 0, 0)),
      sources=[gamma1, gamma2],
      probabilities=[1.0, 0.9988]
  )

Checklist

  • I have performed a self-review of my own code
  • I have run clang-format (version 15) on any C++ source files (if applicable)
  • I have followed the style guidelines for Python source files (if applicable)
  • I have made corresponding changes to the documentation (if applicable)
  • I have added tests that prove my fix is effective or that my feature works (if applicable)

@GuySten
Copy link
Contributor

GuySten commented Feb 9, 2026

I think CoincidentSource is a better name because CorrelatedSource reminds me of correlated probability distributions (for when we want to implement dependent probability distributions).
You also used that name in the pull request title and commit.

Comment on lines +763 to +771
// If all rolls failed, push first sub-source with zero weight so the
// history can still initialize
if (sites.empty()) {
SourceSite site = sources_[0]->sample(seed);
site.r = r;
site.time = time;
site.wgt = 0.0;
sites.push_back(site);
}
Copy link
Contributor

@GuySten GuySten Feb 9, 2026

Choose a reason for hiding this comment

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

I suggest internally scaling the source strength such that you can resampling sites until some particles are emitted.

This is done by multiplying the source strength by the probability of sampling some particles.

Another nice improvement could be to sample directly instead of with rejection sampling.
This is trivial if some independent source has probability 1.
But if all of them have probabilities less than one, this could be done by generating a discrete distribution, sampling the first particle that is guaranteed to exist and then sampling the rest according to their probability.

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.

2 participants