From ef3019a140d7e9b511f7e09bfb029c2b1e1e4015 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 5 Apr 2022 12:49:48 -0500 Subject: [PATCH 1/4] Add merge classmethod on openmc.stats.Discrete --- openmc/stats/univariate.py | 31 +++++++++++++++++++++++++++++++ tests/unit_tests/test_stats.py | 23 +++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/openmc/stats/univariate.py b/openmc/stats/univariate.py index f8e50044f..53b19713b 100644 --- a/openmc/stats/univariate.py +++ b/openmc/stats/univariate.py @@ -1,5 +1,7 @@ from abc import ABC, abstractmethod +from collections import defaultdict from collections.abc import Iterable +from functools import reduce from numbers import Real from xml.etree import ElementTree as ET @@ -156,6 +158,35 @@ class Discrete(Univariate): p = params[len(params)//2:] return cls(x, p) + @classmethod + def merge(cls, dists, probs): + """Merge multiple discrete distributions into a single distribution + + Parameters + ---------- + dists : iterable of openmc.stats.Discrete + Discrete distributions to combine + probs : iterable of float + Probability of each distribution + + Returns + ------- + openmc.stats.Discrete + Combined discrete distribution + + """ + # Combine distributions accounting for duplicate x values + x_merged = set() + p_merged = defaultdict(float) + for dist, p_dist in zip(dists, probs): + for x, p in zip(dist.x, dist.p): + x_merged.add(x) + p_merged[x] += p*p_dist + + # Create values and probabilities as arrays + x_arr = np.array(sorted(x_merged)) + p_arr = np.array([p_merged[x] for x in x_arr]) + return cls(x_arr, p_arr) class Uniform(Univariate): """Distribution with constant probability over a finite interval [a,b] diff --git a/tests/unit_tests/test_stats.py b/tests/unit_tests/test_stats.py index bbcb12ff1..51a561bd3 100644 --- a/tests/unit_tests/test_stats.py +++ b/tests/unit_tests/test_stats.py @@ -27,6 +27,29 @@ def test_discrete(): assert len(d2) == 1 +def test_merge_discrete(): + x1 = [0.0, 1.0, 10.0] + p1 = [0.3, 0.2, 0.5] + d1 = openmc.stats.Discrete(x1, p1) + + x2 = [0.5, 1.0, 5.0] + p2 = [0.4, 0.5, 0.1] + d2 = openmc.stats.Discrete(x2, p2) + + # Merged distribution should have x values sorted and probabilities + # appropriately combined. Duplicate x values should appear once. + merged = openmc.stats.Discrete.merge([d1, d2], [0.6, 0.4]) + 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]) + + # 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]) + + def test_uniform(): a, b = 10.0, 20.0 d = openmc.stats.Uniform(a, b) From 6f1f42e5c5965ade345b0b0924cf725ad8d48bae Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 4 May 2022 07:05:10 -0500 Subject: [PATCH 2/4] Fix docstring for IsogonalOctagon (missing 'r' for raw) --- openmc/model/surface_composite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openmc/model/surface_composite.py b/openmc/model/surface_composite.py index 74f64c54a..6271154fb 100644 --- a/openmc/model/surface_composite.py +++ b/openmc/model/surface_composite.py @@ -212,7 +212,7 @@ class CylinderSector(CompositeSurface): class IsogonalOctagon(CompositeSurface): - """Infinite isogonal octagon composite surface + r"""Infinite isogonal octagon composite surface An isogonal octagon is composed of eight planar surfaces. The prism is parallel to the x, y, or z axis. The remaining two axes (y and z, z and x, From cf665d076fa5d43cd157a70b73b48e7bf3648924 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 4 May 2022 12:34:04 -0500 Subject: [PATCH 3/4] Remove unused import in univariate.py Co-authored-by: Ethan Peterson --- openmc/stats/univariate.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openmc/stats/univariate.py b/openmc/stats/univariate.py index 53b19713b..c9f314793 100644 --- a/openmc/stats/univariate.py +++ b/openmc/stats/univariate.py @@ -1,7 +1,6 @@ from abc import ABC, abstractmethod from collections import defaultdict from collections.abc import Iterable -from functools import reduce from numbers import Real from xml.etree import ElementTree as ET From 178adb084319827c09e7ceac76368a1da829adc1 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 11 May 2022 14:47:07 -0500 Subject: [PATCH 4/4] Consistency check in Discrete.merge method --- openmc/stats/univariate.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openmc/stats/univariate.py b/openmc/stats/univariate.py index c9f314793..e4a9b8f92 100644 --- a/openmc/stats/univariate.py +++ b/openmc/stats/univariate.py @@ -174,6 +174,9 @@ class Discrete(Univariate): Combined discrete distribution """ + if len(dists) != len(probs): + raise ValueError("Number of distributions and probabilities must match.") + # Combine distributions accounting for duplicate x values x_merged = set() p_merged = defaultdict(float)