Skip to content

Commit 619d553

Browse files
committed
Added PolarArbitrary distribution
1 parent d3e98f9 commit 619d553

1 file changed

Lines changed: 74 additions & 2 deletions

File tree

src/attpc_engine/kinematics/angle.py

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def sample(self, rng: Generator) -> float: # type: ignore
2626
2727
Returns
2828
-------
29-
float:
29+
float
3030
The sampled angle in radians
3131
"""
3232
pass
@@ -74,7 +74,79 @@ def sample(self, rng: Generator) -> float:
7474
7575
Returns
7676
-------
77-
float:
77+
float
7878
The sampled angle in radians
7979
"""
8080
return np.arccos(rng.uniform(self.cos_angle_min, self.cos_angle_max))
81+
82+
83+
class PolarArbitrary:
84+
"""An arbitrary, finite-precision polar angular distribution in the CM frame
85+
86+
Define an arbitrary probability distribution for the polar angle using an
87+
array of uniformly-spaced angles and their probabilities, as well as the spacing
88+
of the angle values. We then sample from the distribution and smear the output angle
89+
within the spacing.
90+
91+
Note: If your distribution is defined using *any* of the pre-defined distributions,
92+
you should favor using those over PolarArbitrary. Sampling of arbitrary functions
93+
comes with a runtime performance penalty. That is: do not use this to sample from a
94+
uniform distribution.
95+
96+
Parameters
97+
----------
98+
angles: numpy.ndarray
99+
The array of *lower* angle values. Each angle corresponds to a bin covering
100+
angle + bin_width. Angles should be in units of radians.
101+
probabilities: numpy.ndarray
102+
The probability of a given angle bin. Should sum to 1.0
103+
angle_bin_width: float
104+
The width of the angle bins in radians
105+
106+
Attributes
107+
----------
108+
angle_width: float
109+
The angle bin width in radians
110+
probs: numpy.ndarray
111+
The probability of a given angle bin
112+
angles: numpy.ndarray
113+
The array of *lower* angle values. Each angle corresponds to a bin covering
114+
angle + bin_width. Angles should be in units of radians.
115+
116+
Methods
117+
-------
118+
sample(rng)
119+
Sample the distribution, returning a polar angle in radians
120+
"""
121+
122+
def __init__(
123+
self,
124+
angles: np.ndarray,
125+
probabilities: np.ndarray,
126+
angle_bin_width: float,
127+
):
128+
if np.sum(probabilities) > 1.0:
129+
raise ValueError(
130+
f"The sum of the probabilities passed to PolarArbitrary should be 1.0. Yours sum to {np.sum(probabilities)}"
131+
)
132+
self.angle_width = angle_bin_width
133+
self.probs = probabilities
134+
self.angles = angles
135+
136+
def sample(self, rng: Generator) -> float:
137+
"""Sample the distribution, returning a polar angle in radians
138+
139+
Parameters
140+
----------
141+
rng: numpy.random.Generator
142+
The random number generator
143+
144+
Returns
145+
-------
146+
float
147+
The sampled angle in radians
148+
"""
149+
return (
150+
rng.choice(self.angles, p=self.probs)
151+
+ rng.uniform(0.0, 1.0) * self.angle_width
152+
)

0 commit comments

Comments
 (0)