mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-27 21:55:41 -04:00
Merge pull request #2165 from paulromano/mixture-sample-fix
Fix Mixture.sample to account for intensities of underlying distributions
This commit is contained in:
commit
e794513892
2 changed files with 28 additions and 4 deletions
|
|
@ -79,6 +79,18 @@ class Univariate(EqualityMixin, ABC):
|
|||
"""
|
||||
pass
|
||||
|
||||
def integral(self):
|
||||
"""Return integral of distribution
|
||||
|
||||
.. versionadded:: 0.13.1
|
||||
|
||||
Returns
|
||||
-------
|
||||
float
|
||||
Integral of distribution
|
||||
"""
|
||||
return 1.0
|
||||
|
||||
|
||||
class Discrete(Univariate):
|
||||
"""Distribution characterized by a probability mass function.
|
||||
|
|
@ -1168,9 +1180,17 @@ class Mixture(Univariate):
|
|||
|
||||
def sample(self, n_samples=1, seed=None):
|
||||
np.random.seed(seed)
|
||||
idx = np.random.choice(range(len(self.distribution)),
|
||||
n_samples, p=self.probability)
|
||||
|
||||
# Get probability of each distribution accounting for its intensity
|
||||
p = np.array([prob*dist.integral() for prob, dist in
|
||||
zip(self.probability, self.distribution)])
|
||||
p /= p.sum()
|
||||
|
||||
# Sample from the distributions
|
||||
idx = np.random.choice(range(len(self.distribution)),
|
||||
n_samples, p=p)
|
||||
|
||||
# Draw samples from the distributions sampled above
|
||||
out = np.empty_like(idx, dtype=float)
|
||||
for i in np.unique(idx):
|
||||
n_dist_samples = np.count_nonzero(idx == i)
|
||||
|
|
@ -1294,7 +1314,7 @@ def combine_distributions(dists, probs):
|
|||
|
||||
# Combine discrete and continuous if present
|
||||
if len(dist_list) > 1:
|
||||
probs = [d.integral() for d in dist_list]
|
||||
probs = [1.0]*len(dist_list)
|
||||
dist_list[:] = [Mixture(probs, dist_list.copy())]
|
||||
|
||||
return dist_list[0]
|
||||
|
|
|
|||
|
|
@ -61,12 +61,14 @@ def test_merge_discrete():
|
|||
assert merged.x == pytest.approx([0.0, 0.5, 1.0, 5.0, 10.0])
|
||||
assert merged.p == pytest.approx(
|
||||
[0.6*0.3, 0.4*0.4, 0.6*0.2 + 0.4*0.5, 0.4*0.1, 0.6*0.5])
|
||||
assert merged.integral() == pytest.approx(1.0)
|
||||
|
||||
# Probabilities add up but are not normalized
|
||||
d1 = openmc.stats.Discrete([3.0], [1.0])
|
||||
triple = openmc.stats.Discrete.merge([d1, d1, d1], [1.0, 2.0, 3.0])
|
||||
assert triple.x == pytest.approx([3.0])
|
||||
assert triple.p == pytest.approx([6.0])
|
||||
assert triple.integral() == pytest.approx(6.0)
|
||||
|
||||
|
||||
def test_uniform():
|
||||
|
|
@ -186,6 +188,7 @@ def test_tabular():
|
|||
# test histogram sampling
|
||||
d = openmc.stats.Tabular(x, p, interpolation='histogram')
|
||||
d.normalize()
|
||||
assert d.integral() == pytest.approx(1.0)
|
||||
|
||||
samples = d.sample(n_samples, seed=100)
|
||||
diff = np.abs(samples - d.mean())
|
||||
|
|
@ -433,8 +436,9 @@ def test_combine_distributions():
|
|||
t2 = openmc.stats.Tabular([0., 1.], [0.0, 2.0])
|
||||
d1 = openmc.stats.Discrete([0.0], [1.0])
|
||||
combined = openmc.stats.combine_distributions([t1, t2, d1], [0.25, 0.25, 0.5])
|
||||
assert combined.integral() == pytest.approx(1.0)
|
||||
|
||||
# Sample the combined distribution and make sure the sample mean is within
|
||||
# uncertainty of the expected value
|
||||
samples = combined.sample(1000)
|
||||
samples = combined.sample(10_000)
|
||||
assert_sample_mean(samples, 0.25)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue